diff --git a/0001-add-path-put-in-xattr-set.patch b/0001-add-path-put-in-xattr-set.patch deleted file mode 100644 index 64ae2aba02062f90e740f20df3de7406a79876e5..0000000000000000000000000000000000000000 --- a/0001-add-path-put-in-xattr-set.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 959f29ce47ff71cc40ffbd0857471b79074cb9a5 Mon Sep 17 00:00:00 2001 -From: liqiang -Date: Wed, 30 Nov 2022 20:30:29 +0800 -Subject: [PATCH 1/3] add path put in xattr set - -Signed-off-by: liqiang ---- - qtfs/qtfs_server/fsops.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/qtfs/qtfs_server/fsops.c b/qtfs/qtfs_server/fsops.c -index 6633f3c..48ec7ab 100644 ---- a/qtfs/qtfs_server/fsops.c -+++ b/qtfs/qtfs_server/fsops.c -@@ -843,6 +843,7 @@ int handle_xattrset(struct qtserver_arg *arg) - qtfs_info("handle xattrset path:%s name:%s value:%s ret:%d size:%lu flags:%d", req->buf, - &req->buf[req->d.pathlen], &req->buf[req->d.pathlen + req->d.namelen], rsp->errno, - req->d.size, req->d.flags); -+ path_put(&path); - return sizeof(struct qtrsp_xattrset); - - err_handle: --- -2.23.0 - diff --git a/0001-rewrite-client-rexec_run.patch b/0001-rewrite-client-rexec_run.patch new file mode 100644 index 0000000000000000000000000000000000000000..4c4b0a79ba07105927d04c1890d6a95240e08ed1 --- /dev/null +++ b/0001-rewrite-client-rexec_run.patch @@ -0,0 +1,547 @@ +From 47fdab7bf180b058f6bbed10dd17e9a4c784eecc Mon Sep 17 00:00:00 2001 +From: liqiang +Date: Thu, 1 Jun 2023 15:46:05 +0800 +Subject: rewrite client rexec_run + +Signed-off-by: liqiang +--- + qtfs/rexec/rexec.c | 256 +++++++++++++++++++++++++++++--------- + qtfs/rexec/rexec.h | 8 ++ + qtfs/rexec/rexec_server.c | 51 +++++--- + 3 files changed, 236 insertions(+), 79 deletions(-) + +diff --git a/qtfs/rexec/rexec.c b/qtfs/rexec/rexec.c +index 4dd206d..489ebec 100644 +--- a/qtfs/rexec/rexec.c ++++ b/qtfs/rexec/rexec.c +@@ -42,6 +42,21 @@ + #define REXEC_MSG_LEN 1024 + FILE *rexec_logfile = NULL; + ++struct rexec_global_var { ++ int rexec_hs_fd[2]; ++}; ++ ++struct rexec_global_var g_rexec; ++ ++ ++struct rexec_client_event { ++ int fd; ++ int outfd; // for stdin out err and other pipe ++ int (*handler)(struct rexec_client_event *); ++ int *exit_status; ++ int *pidfd; ++}; ++ + #define REXEC_PIDMAP_PATH "/var/run/rexec/pids" + #define REXEC_PIDMAP_PATH_LEN 64 + #define REXEC_PID_LEN 16 +@@ -84,37 +99,39 @@ static int rexec_msg_fill_argv(int argc, char *argv[], char *msg) + return offset; + } + +-static int rexec_io(int infd, int outfd, char *buf, int buflen) ++static int rexec_io(struct rexec_client_event *evt) + { ++#define MAX_MSG_LEN 256 ++ char buf[MAX_MSG_LEN]; + int len; + int ret; +- while ((len = read(infd, buf, buflen)) > 0) { +- ret = write(outfd, buf, len); ++ while ((len = read(evt->fd, buf, MAX_MSG_LEN)) > 0) { ++ ret = write(evt->outfd, buf, len); + if (ret <= 0) { +- rexec_err("Read from fd:%d len:%d write to fd:%d failed ret:%d", infd, len, outfd, ret); +- return -1; ++ rexec_err("Read from fd:%d len:%d write to fd:%d failed ret:%d", evt->fd, len, evt->outfd, ret); ++ return REXEC_EVENT_EXIT; + } + if (ret != len) { +- rexec_err("Read from fd:%d len:%d but write to fd:%d ret:%d", infd, len, outfd, ret); ++ rexec_err("Read from fd:%d len:%d but write to fd:%d ret:%d", evt->fd, len, evt->outfd, ret); + } + } +- return 0; ++ return REXEC_EVENT_OK; + } + + // return -1 means process exit. +-static int rexec_conn_msg(int connfd, int *exit_status, int *pidfd) ++static int rexec_conn_msg(struct rexec_client_event *evt) + { + struct rexec_msg head; +- int ret = recv(connfd, &head, sizeof(struct rexec_msg), MSG_WAITALL); ++ int ret = recv(evt->fd, &head, sizeof(struct rexec_msg), MSG_WAITALL); + if (ret <= 0) { + rexec_err("Rexec conn recv err:%d errno:%d", ret, errno); +- return -1; ++ return REXEC_EVENT_EXIT; + } + switch (head.msgtype) { + case REXEC_KILL: +- *exit_status = head.exit_status; ++ *evt->exit_status = head.exit_status; + rexec_err("Rexec conn recv kill msg, exit:%d now.", head.exit_status); +- return -1; ++ return REXEC_EVENT_EXIT; + case REXEC_PIDMAP: { + int mypid = getpid(); + int peerpid = head.pid; +@@ -122,9 +139,9 @@ static int rexec_conn_msg(int connfd, int *exit_status, int *pidfd) + char buf[REXEC_PID_LEN] = {0}; + int fd; + int err; +- if (*pidfd > 0) { ++ if (*evt->pidfd > 0) { + rexec_err("Rexec pidmap msg > 1 error."); +- return 0; ++ return REXEC_EVENT_OK; + } + sprintf(path, "%s/%d", REXEC_PIDMAP_PATH, mypid); + fd = open(path, O_CREAT|O_WRONLY, 0600); +@@ -133,23 +150,41 @@ static int rexec_conn_msg(int connfd, int *exit_status, int *pidfd) + mypid, peerpid, path, fd); + break; + } +- *pidfd = fd; ++ *evt->pidfd = fd; + if ((err = flock(fd, LOCK_EX)) != 0) { + rexec_err("Rexec flock file:%s failed, errno:%d rexec exit.", path, err); +- return -1; ++ return REXEC_EVENT_EXIT; + } + if ((err = ftruncate(fd, 0)) != 0) { + rexec_err("Rexec pidmap file:%s clear failed errno:%d rexec exit.", path, err); +- return -1; ++ return REXEC_EVENT_EXIT; + } + if ((err = lseek(fd, 0, SEEK_SET)) < 0) { + rexec_err("Rexec pidmap file:%s lseek 0 failed errno:%d rexec exit", path, err); +- return -1; ++ return REXEC_EVENT_EXIT; + } + sprintf(buf, "%d", peerpid); + if ((err = write(fd, buf, strlen(buf))) <= 0) { + rexec_err("Rexec pidmap file:%s write pid:%d failed errno:%d rexec exit.", path, peerpid, err); +- return -1; ++ return REXEC_EVENT_EXIT; ++ } ++ if (g_rexec.rexec_hs_fd[PIPE_WRITE] != -1 && g_rexec.rexec_hs_fd[PIPE_READ] != -1) { ++ err = write(g_rexec.rexec_hs_fd[PIPE_WRITE], "1", 1); ++ if (err <= 0) { ++ rexec_err("rexec handshake write 1 failed, hs write:%d.", g_rexec.rexec_hs_fd[PIPE_WRITE]); ++ return REXEC_EVENT_ERR; ++ } ++ } else { ++ char msg[sizeof(struct rexec_msg) + 1]; ++ struct rexec_msg *hs = msg; ++ char *ok = hs->msg; ++ hs->msgtype = REXEC_HANDSHAKE; ++ hs->msglen = 1; ++ *ok = '1'; ++ if (write(evt->fd, hs, sizeof(struct rexec_msg) + 1) <= 0) { ++ rexec_err("send handshake failed, remote process will die"); ++ return REXEC_EVENT_EXIT; ++ } + } + break; + } +@@ -159,6 +194,35 @@ static int rexec_conn_msg(int connfd, int *exit_status, int *pidfd) + + rexec_log("Rexec conn recv msgtype:%d argc:%d stdno:%d msglen:%d", + head.msgtype, head.argc, head.stdno, head.msglen); ++ return REXEC_EVENT_OK; ++} ++ ++static struct rexec_client_event *rexec_add_event(int efd, int fd, int outfd, int (*handler)(struct rexec_client_event *)) ++{ ++ struct rexec_client_event *event = (struct rexec_client_event *)malloc(sizeof(struct rexec_client_event)); ++ if (event == NULL) { ++ rexec_err("malloc failed."); ++ return NULL; ++ } ++ event->fd = fd; ++ event->outfd = outfd; ++ event->handler = handler; ++ struct epoll_event evt; ++ evt.data.ptr = (void *)event; ++ evt.events = EPOLLIN; ++ if (-1 == epoll_ctl(efd, EPOLL_CTL_ADD, event->fd, &evt)) { ++ rexec_err("epoll ctl add fd:%d event failed.", event->fd); ++ free(event); ++ return NULL; ++ } ++ return event; ++} ++ ++static int rexec_del_event(struct rexec_client_event *event) ++{ ++ // close will del fd in epoll list ++ close(event->fd); ++ free(event); + return 0; + } + +@@ -166,48 +230,48 @@ enum { + REPOL_IN_INDEX = 0, + REPOL_OUT_INDEX, + REPOL_ERR_INDEX, +- REPOL_CONN_INDEX, + REPOL_INV_INDEX, + }; +-static int rexec_run(int rstdin, int rstdout, int rstderr, int connfd, char *argv[]) ++static int rexec_std_event(int efd, int rstdin, int rstdout, int rstderr) + { +- int exit_status = EXIT_FAILURE; +-#define REXEC_MAX_EVENTS 4 +- int infds[4] = {STDIN_FILENO, rstdout, rstderr, connfd}; +- int outfds[4] = {rstdin, STDOUT_FILENO, STDERR_FILENO, connfd}; ++ #define REXEC_MAX_EVENTS 4 ++ int infds[REPOL_INV_INDEX] = {STDIN_FILENO, rstdout, rstderr}; ++ int outfds[REPOL_INV_INDEX] = {rstdin, STDOUT_FILENO, STDERR_FILENO}; + +- int efd = epoll_create1(0); +- if (efd == -1) { +- rexec_err("epoll create1 failed, errno:%d.", errno); +- return exit_status; +- } +- struct epoll_event evt; + for (int i = 0; i < REPOL_INV_INDEX; i++) { +- evt.data.u32 = i; +- evt.events = EPOLLIN; +- if (-1 == epoll_ctl(efd, EPOLL_CTL_ADD, infds[i], &evt)) { ++ if (NULL == rexec_add_event(efd, infds[i], outfds[i], rexec_io)) { + rexec_err("epoll ctl add fd:%d event failed and ignore this mistake.", infds[i]); + continue; + } else { + if (rexec_set_nonblock(infds[i], 1) != 0) { + rexec_err("rexec set fd:%d i:%d non block failed.", infds[i], i); +- return exit_status; ++ return -1; + } + } + } ++ return 0; ++} ++ ++static int rexec_run(int efd, int connfd, char *argv[]) ++{ ++ int pidfd = -1; ++ int exit_status = EXIT_FAILURE; ++ ++ struct rexec_client_event *connevt = rexec_add_event(efd, connfd, -1, rexec_conn_msg); ++ if (NULL == connevt || rexec_set_nonblock(connfd, 1) != 0) { ++ // process will exit, fd or mem resource will free by kernel soon ++ rexec_err("rexec add connfd event failed"); ++ return exit_status; ++ } ++ // 这两个指针只能在当前函数上下文使用,是当前函数栈指针 ++ connevt->exit_status = &exit_status; ++ connevt->pidfd = &pidfd; + + struct epoll_event *evts = calloc(REXEC_MAX_EVENTS, sizeof(struct epoll_event)); + if (evts == NULL) { + rexec_err("init calloc evts failed."); + goto end; + } +- int buflen = REXEC_MSG_LEN; +- char *buf = (char *)malloc(buflen); +- int pidfd = -1; +- if (buf == NULL) { +- rexec_err("Rexec malloc failed."); +- goto free_end; +- } + rexec_log("Rexec process start run, as proxy of remote %s", argv[1]); + while (1) { + int n = epoll_wait(efd, evts, REXEC_MAX_EVENTS, 1000); +@@ -219,23 +283,16 @@ static int rexec_run(int rstdin, int rstdout, int rstderr, int connfd, char *arg + continue; + } + for (int i = 0; i < n; i++) { +- int infd = -1; +- int outfd = -1; +- if (evts[i].data.u32 >= REPOL_INV_INDEX) { +- rexec_err("invalid epoll events index data:%d", evts[i].data.u32); +- continue; ++ struct rexec_client_event *evt = (struct rexec_client_event *)evts[i].data.ptr; ++ int ret = evt->handler(evt); ++ if (evts[i].events & EPOLLHUP || ret == REXEC_EVENT_EXIT) { ++ process_exit = 1; + } +- infd = infds[evts[i].data.u32]; +- outfd = outfds[evts[i].data.u32]; +- if (infd == connfd) { +- if (evts[i].events & EPOLLHUP || rexec_conn_msg(connfd, &exit_status, &pidfd) == -1) +- process_exit = 1; +- } else { +- if (rexec_io(infd, outfd, buf, buflen) == -1) { +- close(infd); +- } ++ if (ret == REXEC_EVENT_DEL) { ++ rexec_del_event(evt); + } + } ++ // process will exit, and free all resource and exit + if (process_exit) { + rexec_log("Rexec process %s exit.", argv[1]); + break; +@@ -250,8 +307,6 @@ static int rexec_run(int rstdin, int rstdout, int rstderr, int connfd, char *arg + remove(path); + } + +- free(buf); +- + free_end: + free(evts); + +@@ -319,7 +374,7 @@ struct rexec_fdinfo { + int offset; + }; + +-static inline int rexec_is_reg_file(int fd) ++static inline unsigned int rexec_fd_mode(int fd) + { + struct stat st; + char path[32] = {0}; +@@ -327,9 +382,13 @@ static inline int rexec_is_reg_file(int fd) + rexec_err("get fd:%d fstat failed, errno:%d", fd, errno); + return 0; + } +- if (S_ISREG(st.st_mode)) { ++ return st.st_mode; ++} ++ ++static inline int rexec_is_reg_file(int fd) ++{ ++ if (S_ISREG(rexec_fd_mode(fd))) + return 1; +- } + return 0; + } + +@@ -429,16 +488,85 @@ err_end: + return NULL; + } + ++static int rexec_handshake_proc(struct rexec_client_event *evt) ++{ ++ char msg[sizeof(struct rexec_msg) + 1]; ++ struct rexec_msg *hs = msg; ++ int ret = read(evt->fd, hs->msg, 1); ++ if (ret <= 0) { ++ rexec_err("read from handshake pipe failed, ret:%d err:%d", ret, errno); ++ return REXEC_EVENT_DEL; ++ } ++ hs->msgtype = REXEC_HANDSHAKE; ++ hs->msglen = 1; ++ ret = write(evt->outfd, hs, sizeof(struct rexec_msg) + 1); ++ if (ret < 0) { ++ rexec_err("send handshake failed, connfd:%d.", evt->outfd); ++ } ++ return REXEC_EVENT_OK; ++} ++ ++static int rexec_handshake_init(int efd, int connfd) ++{ ++ char *hs_read = getenv("REXEC_HANDSHAKE_RD"); ++ char *hs_write = getenv("REXEC_HANDSHAKE_WR"); ++ ++ if (hs_read == NULL || hs_write == NULL) { ++ rexec_log("handshake not in effect, read:%lx write%lx", hs_read, hs_write); ++ return 0; ++ } ++ g_rexec.rexec_hs_fd[PIPE_READ] = atoi(hs_read); ++ g_rexec.rexec_hs_fd[PIPE_WRITE] = atoi(hs_write); ++ if (g_rexec.rexec_hs_fd[PIPE_READ] <= STDERR_FILENO || g_rexec.rexec_hs_fd[PIPE_WRITE] <= STDERR_FILENO) { ++ rexec_log("handshake invalid fd read:%d write:%d", g_rexec.rexec_hs_fd[PIPE_READ], g_rexec.rexec_hs_fd[PIPE_WRITE]); ++ goto err_end; ++ } ++ if (!S_ISFIFO(rexec_fd_mode(g_rexec.rexec_hs_fd[PIPE_READ])) || !S_ISFIFO(rexec_fd_mode(g_rexec.rexec_hs_fd[PIPE_WRITE]))) { ++ rexec_err("handshake fd mode not fifo:%d %d", g_rexec.rexec_hs_fd[PIPE_READ], g_rexec.rexec_hs_fd[PIPE_WRITE]); ++ goto err_end; ++ } ++ if (rexec_add_event(efd, g_rexec.rexec_hs_fd[PIPE_READ], connfd, rexec_handshake_proc) == NULL) { ++ rexec_err("add handshake pipe read fd:%d to epoll failed", g_rexec.rexec_hs_fd[PIPE_READ]); ++ goto err_end; ++ } ++ rexec_log("handshake effect read:%d write:%d", g_rexec.rexec_hs_fd[PIPE_READ], g_rexec.rexec_hs_fd[PIPE_WRITE]); ++ return 0; ++err_end: ++ g_rexec.rexec_hs_fd[PIPE_READ] = -1; ++ g_rexec.rexec_hs_fd[PIPE_WRITE] = -1; ++ return -1; ++} ++ ++static void rexec_global_var_init() ++{ ++ memset(&g_rexec, 0, sizeof(g_rexec)); ++ g_rexec.rexec_hs_fd[PIPE_READ] = -1; ++ g_rexec.rexec_hs_fd[PIPE_WRITE] = -1; ++ return; ++} ++ + int main(int argc, char *argv[]) + { + rexec_log_init(); + rexec_clear_pids(); + ++ int efd = epoll_create1(0); ++ if (efd == -1) { ++ rexec_err("epoll create1 failed, errno:%d.", errno); ++ return -1; ++ } ++ rexec_global_var_init(); ++ + int connfd = rexec_conn_to_server(); + if (connfd < 0) { + rexec_err("Rexec connect to server failed, errno:%d", errno); + return -1; + } ++ ++ if (rexec_handshake_init(efd, connfd) != 0) { ++ rexec_err("Rexec handshake environment set but get error."); ++ return -1; ++ } + rexec_log("Remote exec binary:%s", argv[1]); + + int arglen = rexec_calc_argv_len(argc - 1, &argv[1]); +@@ -513,7 +641,11 @@ int main(int argc, char *argv[]) + close(rstdin[0]); + close(rstdout[1]); + close(rstderr[1]); +- exit_status = rexec_run(rstdin[1], rstdout[0], rstderr[0], connfd, argv); ++ if (rexec_std_event(efd, rstdin[1], rstdout[0], rstderr[0]) != 0) { ++ rexec_err("add std event failed"); ++ goto err_end; ++ } ++ exit_status = rexec_run(efd, connfd, argv); + close(rstdin[1]); + close(rstdout[0]); + close(rstderr[0]); +diff --git a/qtfs/rexec/rexec.h b/qtfs/rexec/rexec.h +index ba7c2be..ce1280a 100644 +--- a/qtfs/rexec/rexec.h ++++ b/qtfs/rexec/rexec.h +@@ -24,6 +24,13 @@ enum { + PIPE_WRITE, + }; + ++enum { ++ REXEC_EVENT_OK, ++ REXEC_EVENT_DEL, // del this event ++ REXEC_EVENT_EXIT, // exit process ++ REXEC_EVENT_ERR, ++}; ++ + enum { + REXEC_STDIN = 0x5a, + REXEC_STDOUT, +@@ -45,6 +52,7 @@ enum rexec_msgtype { + REXEC_KILL, // kill process + REXEC_PIPE, // client send a pipefd as stdin/out/err to server + REXEC_PIDMAP, // server send remote process's pid to client ++ REXEC_HANDSHAKE, + }; + + struct rexec_msg { +diff --git a/qtfs/rexec/rexec_server.c b/qtfs/rexec/rexec_server.c +index 686c051..2aa3275 100644 +--- a/qtfs/rexec/rexec_server.c ++++ b/qtfs/rexec/rexec_server.c +@@ -65,12 +65,6 @@ struct rexec_event { + int (*handler)(struct rexec_event *); + }; + +-enum { +- REXEC_EVENT_OK, +- REXEC_EVENT_ERR, +- REXEC_EVENT_DEL, +-}; +- + static int rexec_add_event(int efd, int fd, int pid, int (*handler)(struct rexec_event *)) + { + struct rexec_event *event = (struct rexec_event *)malloc(sizeof(struct rexec_event)); +@@ -86,6 +80,7 @@ static int rexec_add_event(int efd, int fd, int pid, int (*handler)(struct rexec + evt.events = EPOLLIN; + if (-1 == epoll_ctl(efd, EPOLL_CTL_ADD, event->fd, &evt)) { + rexec_err("epoll ctl add fd:%d event failed.", event->fd); ++ free(event); + return -1; + } + return 0; +@@ -136,15 +131,6 @@ static int rexec_event_handshake(struct rexec_event *event) + rexec_log("Rexec recv son pid:%d, connfd:%d", sonpid, connfd); + + rexec_hash_insert_direct(child_hash, sonpid, connfd); +- +- struct rexec_msg head; +- head.msgtype = REXEC_PIDMAP; +- head.msglen = 0; +- head.pid = sonpid; +- ret = write(connfd, &head, sizeof(struct rexec_msg)); +- if (ret <= 0) { +- rexec_err("Rexec send son pid:%d to client failed, ret:%d errno:%d", sonpid, ret, errno); +- } + rexec_add_event(main_epoll_fd, connfd, sonpid, rexec_event_process_manage); + + // 成功后同样要删除这个pipe监听事件,删除时会close掉fd +@@ -326,7 +312,7 @@ static int rexec_start_new_process(int newconnfd) + int scmfd = -1; + int len = sizeof(struct rexec_msg); + memset(&head, 0, sizeof(struct rexec_msg)); +- int ret = rexec_recvmsg(newconnfd, (char *)&head, len, &scmfd, MSG_WAITALL); ++ ret = rexec_recvmsg(newconnfd, (char *)&head, len, &scmfd, MSG_WAITALL); + if (ret <= 0) { + rexec_log("recvmsg ret:%d, errno:%d", ret, errno); + goto err_to_parent; +@@ -375,14 +361,45 @@ static int rexec_start_new_process(int newconnfd) + goto err_free; + } + ++ char *ack; + int mypid = getpid(); ++ char msg[sizeof(struct rexec_msg) + 1]; ++ struct rexec_msg *pm = msg; ++ pm->msgtype = REXEC_PIDMAP; ++ pm->msglen = 0; ++ pm->pid = mypid; ++ ret = write(newconnfd, pm, sizeof(struct rexec_msg)); ++ if (ret <= 0) { ++ rexec_err("Rexec send son pid:%d to client failed, ret:%d errno:%d", mypid, ret, errno); ++ } else { ++retry: ++ rexec_log("Waiting for rexec client handshake..."); ++ ret = read(newconnfd, pm, sizeof(struct rexec_msg) + 1); ++ if (ret <= 0) { ++ rexec_err("Recv handshake failed, ret:%d err:%d", ret, errno); ++ goto err_to_parent; ++ } ++ if (pm->msgtype != REXEC_HANDSHAKE) { ++ rexec_err("Recv unexpected msg:%d", pm->msgtype); ++ goto retry; ++ } ++ ack = pm->msg; ++ if (*ack != '1') { ++ rexec_err("recv error handshake ack from client:%c, exit now", *ack); ++ goto err_to_parent; ++ } ++ } + // 写会PID必须放在基于newconnfd接收完所有消息之后, + // 后面newconnfd的控制权交回父进程rexec server服务进程 +- write(pipefd[PIPE_WRITE], &mypid, sizeof(int)); ++ if (write(pipefd[PIPE_WRITE], &mypid, sizeof(int)) <= 0) { ++ rexec_err("write pid to parent failed, pipefd:%d.", pipefd[PIPE_WRITE]); ++ } + // 子进程不再使用pipe write和connfd + close(pipefd[PIPE_WRITE]); + close(newconnfd); + ++ rexec_log("handshake over normaly, continue to exec new process:%s.", binary); ++ + // rexec_shim_entry argv like: + // argv[0]: binary + // argv[1]: -f +-- +2.33.0 + diff --git a/0002-Add-drop-link-and-dentry-invalid-in-unlink-and-rmdir.patch b/0002-Add-drop-link-and-dentry-invalid-in-unlink-and-rmdir.patch deleted file mode 100644 index caa370851753032a4db98e639a0caa3310144d35..0000000000000000000000000000000000000000 --- a/0002-Add-drop-link-and-dentry-invalid-in-unlink-and-rmdir.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 0038843dcd4ce52ce3ef2e9dd5ec145211e0f09c Mon Sep 17 00:00:00 2001 -From: yangxin <245051644@qq.com> -Date: Mon, 5 Dec 2022 10:42:04 +0800 -Subject: [PATCH 2/3] Add drop link and dentry invalid in unlink and rmdir. - -Signed-off-by: yangxin <245051644@qq.com> ---- - qtfs/qtfs/sb.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/qtfs/qtfs/sb.c b/qtfs/qtfs/sb.c -index 4ad4aed..5fd2c8f 100644 ---- a/qtfs/qtfs/sb.c -+++ b/qtfs/qtfs/sb.c -@@ -989,6 +989,7 @@ int qtfs_rmdir(struct inode *dir, struct dentry *dentry) - struct qtreq_rmdir *req; - struct qtrsp_rmdir *rsp; - int ret; -+ struct inode *inode = d_inode(dentry); - - if (!pvar) { - qtfs_err("Failed to get qtfs sock var\n"); -@@ -1012,6 +1013,9 @@ int qtfs_rmdir(struct inode *dir, struct dentry *dentry) - } - qtfs_info("qtfs rmdir success:<%s>.\n", req->path); - qtfs_conn_put_param(pvar); -+ if (inode->i_nlink > 0) -+ drop_nlink(inode); -+ d_invalidate(dentry); - return 0; - } - -@@ -1046,6 +1050,9 @@ int qtfs_unlink(struct inode *dir, struct dentry *dentry) - } - ret = rsp->errno; - qtfs_conn_put_param(pvar); -+ if (inode->i_nlink > 0) -+ drop_nlink(inode); -+ d_invalidate(dentry); - return ret; - } - --- -2.23.0 - diff --git a/0002-uds-add-vsock-mode.patch b/0002-uds-add-vsock-mode.patch new file mode 100644 index 0000000000000000000000000000000000000000..2d18fd31a50e398fdfc569223f1589d0e53f4298 --- /dev/null +++ b/0002-uds-add-vsock-mode.patch @@ -0,0 +1,171 @@ +From 9816a45d35ffa187b5830a417147afa9695dcead Mon Sep 17 00:00:00 2001 +From: liqiang +Date: Sat, 3 Jun 2023 11:01:23 +0800 +Subject: uds add vsock mode + +Signed-off-by: liqiang +--- + qtfs/ipc/Makefile | 7 +++++++ + qtfs/ipc/uds_main.c | 43 ++++++++++++++++++++++++++++++++++++++----- + qtfs/ipc/uds_main.h | 12 +++++++++--- + 3 files changed, 54 insertions(+), 8 deletions(-) + +diff --git a/qtfs/ipc/Makefile b/qtfs/ipc/Makefile +index 2136f4f..3b851f3 100644 +--- a/qtfs/ipc/Makefile ++++ b/qtfs/ipc/Makefile +@@ -3,6 +3,9 @@ CFLAGS += -g -O2 + CFLAGS += -fstack-protector-strong + CFLAGS += -fPIE -pie -fPIC + CFLAGS += -D_FORTIFY_SOURCE=2 ++ifdef UDS_TEST_MODE ++CFLAGS += -DUDS_TEST_MODE ++endif + LDFLAGS += -s + LDFLAGS += -Wl,-z,now + LDFLAGS += -Wl,-z,noexecstack +@@ -12,6 +15,10 @@ all: udsproxyd libudsproxy.so + + udsproxyd: uds_event.o uds_main.o + gcc $(LDFLAGS) -o udsproxyd $^ -I../ $(DEPGLIB) ++ @test -z $(UDS_TEST_MODE) || echo "Important risk warning: The test mode is turned on,\ ++ and udsproxyd will expose the network port, which will bring security risks and is only for\ ++ testing! If you do not understand the risks, please don't use or compile again without\ ++ UDS_TEST_MODE." + + uds_event.o: + cc $(CFLAGS) -c -o uds_event.o uds_event.c $(DEPGLIB) +diff --git a/qtfs/ipc/uds_main.c b/qtfs/ipc/uds_main.c +index 2af4f06..adf0936 100644 +--- a/qtfs/ipc/uds_main.c ++++ b/qtfs/ipc/uds_main.c +@@ -37,6 +37,7 @@ + #include + #include + #include ++#include + + #include "comm.h" + #include "uds_main.h" +@@ -179,15 +180,24 @@ void uds_main_loop(int efd, struct uds_thread_arg *arg) + #define UDS_MAX_LISTEN_NUM 64 + int uds_build_tcp_connection(struct uds_conn_arg *arg) + { ++ int family = AF_VSOCK; + if (arg->cs > UDS_SOCKET_SERVER) { + uds_err("cs type %d is error.", arg->cs); + return -1; + } +- struct sockaddr_in sock_addr = { +- .sin_family = AF_INET, +- }; +- int sock_fd = socket(AF_INET, SOCK_STREAM, 0); ++#ifdef UDS_TEST_MODE ++ family = AF_INET; ++ struct sockaddr_in sock_addr; ++ memset(&sock_addr, 0, sizeof(sock_addr)); ++ sock_addr.sin_family = AF_INET; ++#else ++ family = AF_VSOCK; ++ struct sockaddr_vm sock_addr; ++ memset(&sock_addr, 0, sizeof(sock_addr)); ++ sock_addr.svm_family = AF_VSOCK; ++#endif + ++ int sock_fd = socket(family, SOCK_STREAM, 0); + if (sock_fd < 0) { + uds_err("As %s failed, socket fd: %d, errno:%d.", + (arg->cs == UDS_SOCKET_CLIENT) ? "client" : "server", +@@ -197,8 +207,13 @@ int uds_build_tcp_connection(struct uds_conn_arg *arg) + arg->sockfd = sock_fd; + + if (arg->cs == UDS_SOCKET_SERVER) { ++#ifdef UDS_TEST_MODE + sock_addr.sin_port = htons(p_uds_var->tcp.port); + sock_addr.sin_addr.s_addr = inet_addr(p_uds_var->tcp.addr); ++#else ++ sock_addr.svm_port = p_uds_var->vsock.port; ++ sock_addr.svm_cid = p_uds_var->vsock.cid; ++#endif + if (bind(sock_fd, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) < 0) { + uds_err("As tcp server failed, bind error, errno:%d.", + errno); +@@ -209,13 +224,22 @@ int uds_build_tcp_connection(struct uds_conn_arg *arg) + goto close_and_return; + } + } else { ++#ifdef UDS_TEST_MODE + sock_addr.sin_port = htons(p_uds_var->tcp.peerport); + sock_addr.sin_addr.s_addr = inet_addr(p_uds_var->tcp.peeraddr); +- if (connect(arg->sockfd, (struct sockaddr *)&sock_addr, sizeof(struct sockaddr_in)) < 0) { ++#else ++ sock_addr.svm_port = p_uds_var->vsock.peerport; ++ sock_addr.svm_cid = p_uds_var->vsock.peercid; ++#endif ++ if (connect(arg->sockfd, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) < 0) { + goto close_and_return; + } + arg->connfd = sock_fd; ++#ifdef UDS_TEST_MODE + uds_log("Connect to tcp server successed, ip:%s port:%u", p_uds_var->tcp.peeraddr, p_uds_var->tcp.peerport); ++#else ++ uds_log("Connect to vsock server successed, cid:%u port:%u", p_uds_var->vsock.peercid, p_uds_var->vsock.peerport); ++#endif + } + + return 0; +@@ -599,6 +623,7 @@ static int uds_glob_var_init(char *argv[]) + uds_err("work thread var malloc failed."); + return -1; + } ++#ifdef UDS_TEST_MODE + p_uds_var->tcp.port = atoi(argv[3]); + strncpy(p_uds_var->tcp.addr, argv[2], sizeof(p_uds_var->tcp.addr) - 1); + p_uds_var->tcp.peerport = atoi(argv[5]); +@@ -607,6 +632,14 @@ static int uds_glob_var_init(char *argv[]) + uds_log("uds proxy param thread num:%d ip:%s port:%u peerip:%s port:%u", + p_uds_var->work_thread_num, p_uds_var->tcp.addr, p_uds_var->tcp.port, + p_uds_var->tcp.peeraddr, p_uds_var->tcp.peerport); ++#else ++ // vsock param: ++ // port and peerport is checked before ++ p_uds_var->vsock.cid = atoi(argv[2]); ++ p_uds_var->vsock.port = myport; ++ p_uds_var->vsock.peercid = atoi(argv[4]); ++ p_uds_var->vsock.peerport = peerport; ++#endif + g_event_var = (struct uds_event_global_var *)malloc(sizeof(struct uds_event_global_var) * p_uds_var->work_thread_num); + if (g_event_var == NULL) { + free(p_uds_var->efd); +diff --git a/qtfs/ipc/uds_main.h b/qtfs/ipc/uds_main.h +index 3903ec8..de400f8 100644 +--- a/qtfs/ipc/uds_main.h ++++ b/qtfs/ipc/uds_main.h +@@ -111,15 +111,21 @@ struct uds_global_var { + struct uds_thread_arg *work_thread; + int loglevel; + char **logstr; ++#ifdef UDS_TEST_MODE + struct _tcp { + char addr[20]; + unsigned short port; + char peeraddr[20]; + unsigned short peerport; + } tcp; +- struct _uds { +- char sun_path[UDS_SUN_PATH_LEN]; +- } uds; ++#else ++ struct _vsock { ++ unsigned int cid; ++ unsigned int port; ++ unsigned int peercid; ++ unsigned int peerport; ++ } vsock; ++#endif + }; + enum uds_cs { + UDS_SOCKET_CLIENT = 1, +-- +2.33.0 + diff --git a/0003-enable-rexec-read-net-addr-from-config-file.patch b/0003-enable-rexec-read-net-addr-from-config-file.patch deleted file mode 100644 index 230f29fc5a331436208d56ee154ede0c270300a0..0000000000000000000000000000000000000000 --- a/0003-enable-rexec-read-net-addr-from-config-file.patch +++ /dev/null @@ -1,119 +0,0 @@ -From 7dfd4ec8ee7ab9034b35061567235c62d8c5522e Mon Sep 17 00:00:00 2001 -From: YangXin <245051644@qq.com> -Date: Mon, 5 Dec 2022 21:43:26 +0800 -Subject: [PATCH 3/3] enable rexec read net addr from config file. - -Signed-off-by: YangXin <245051644@qq.com> ---- - qtfs/rexec/client.go | 3 ++- - qtfs/rexec/common.go | 33 +++++++++++++++++++++++++++++++-- - qtfs/rexec/server.go | 6 +++++- - 3 files changed, 38 insertions(+), 4 deletions(-) - -diff --git a/qtfs/rexec/client.go b/qtfs/rexec/client.go -index 922040d..13b63f5 100644 ---- a/qtfs/rexec/client.go -+++ b/qtfs/rexec/client.go -@@ -18,6 +18,7 @@ import ( - - const ( - rexecPidDir = "/var/run/rexec/pids" -+ role = "client" - ) - - var pidPath string -@@ -111,7 +112,7 @@ func main() { - if err := SetParentDeathSignal(uintptr(syscall.SIGHUP)); err != nil { - log.Printf("Failed to set Parent Death Signal:%s", err.Error()) - } -- na, err := parseNetAddr() -+ na, err := parseNetAddr(role) - if err != nil { - log.Fatal(err) - } -diff --git a/qtfs/rexec/common.go b/qtfs/rexec/common.go -index a332fae..9ce21c4 100644 ---- a/qtfs/rexec/common.go -+++ b/qtfs/rexec/common.go -@@ -8,10 +8,16 @@ import ( - "os" - "strconv" - "strings" -+ "io/ioutil" -+ "encoding/json" - - "github.com/docker/libchan" - ) - -+const ( -+ configDir = "/etc/rexec" -+) -+ - // RemoteCommand is the run parameters to be executed remotely - type RemoteCommand struct { - Cmd string -@@ -82,12 +88,35 @@ func parseUnixAddr(inAddr string) (NetAddr, error) { - }, nil - } - --func parseNetAddr() (NetAddr, error) { -+func readAddrFromFile(role string) (string) { -+ fileName := fmt.Sprintf("%s/%s.json", configDir, role) -+ file, err := ioutil.ReadFile(fileName) -+ if err != nil { -+ fmt.Printf("read %s failed: %s", fileName, err) -+ return "" -+ } -+ var netAddr struct { -+ Protocol string `json:"Protocol"` -+ Ipaddr string `json:"Ipaddr"` -+ Port string `json:"Port"` -+ } -+ err = json.Unmarshal([]byte(file), &netAddr) -+ if err != nil { -+ fmt.Printf("can not unmarshal %s:%s", fileName, err) -+ return "" -+ } -+ return fmt.Sprintf("%s://%s:%s", netAddr.Protocol, netAddr.Ipaddr, netAddr.Port) -+} -+ -+func parseNetAddr(role string) (NetAddr, error) { - cna := os.Getenv("CMD_NET_ADDR") - - // default netAddr: tcp://127.0.0.1:9323 - if strings.TrimSpace(cna) == "" { -- return NetAddr{}, fmt.Errorf("need CMD_NET_ADDR") -+ cna = readAddrFromFile(role) -+ if cna == "" { -+ return NetAddr{}, fmt.Errorf("please set enviroment variable CMD_NET_ADDR or set Config file %s/%s.json", configDir, role) -+ } - } - - parts := strings.SplitN(cna, "://", 2) -diff --git a/qtfs/rexec/server.go b/qtfs/rexec/server.go -index 4e910ea..4559b79 100644 ---- a/qtfs/rexec/server.go -+++ b/qtfs/rexec/server.go -@@ -15,6 +15,10 @@ import ( - "github.com/docker/libchan/spdy" - ) - -+const ( -+ role = "server" -+) -+ - func getHost(addr string) string { - return strings.Split(addr, ":")[0] - } -@@ -24,7 +28,7 @@ func main() { - key := os.Getenv("TLS_KEY") - - var listener net.Listener -- na, err := parseNetAddr() -+ na, err := parseNetAddr(role) - if err != nil { - log.Fatal(err) - } --- -2.23.0 - diff --git a/0003-fix-a-rexec_server-bug-on-child-process.patch b/0003-fix-a-rexec_server-bug-on-child-process.patch new file mode 100644 index 0000000000000000000000000000000000000000..6cbf848dd4113cd9832131d00bdd4b0a1d9a7649 --- /dev/null +++ b/0003-fix-a-rexec_server-bug-on-child-process.patch @@ -0,0 +1,26 @@ +From 754345d6dffc581e81670f4d1b18396003349a18 Mon Sep 17 00:00:00 2001 +From: liqiang +Date: Mon, 5 Jun 2023 17:24:10 +0800 +Subject: fix a rexec_server bug on child process + +Signed-off-by: liqiang +--- + qtfs/rexec/rexec_server.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/qtfs/rexec/rexec_server.c b/qtfs/rexec/rexec_server.c +index 2aa3275..bdc6ea4 100644 +--- a/qtfs/rexec/rexec_server.c ++++ b/qtfs/rexec/rexec_server.c +@@ -431,7 +431,7 @@ err_to_parent: + write(pipefd[PIPE_WRITE], &errpid, sizeof(int)); + } while (0); + +- return ret; ++ exit(0); + } + + // 道生一 +-- +2.33.0 + diff --git a/0004-Fix-inode-sync-error-between-client-and-server.patch b/0004-Fix-inode-sync-error-between-client-and-server.patch deleted file mode 100644 index 2ebc11b23b8685456bc4becdfcffca48dfe11d2d..0000000000000000000000000000000000000000 --- a/0004-Fix-inode-sync-error-between-client-and-server.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 86c4ef6bc5d845b0c1919ddb80702f2896a75d4f Mon Sep 17 00:00:00 2001 -From: yangxin <245051644@qq.com> -Date: Thu, 15 Dec 2022 10:14:53 +0800 -Subject: [PATCH 4/4] Fix inode sync error between client and server. - -Signed-off-by: yangxin <245051644@qq.com> ---- - qtfs/qtfs/sb.c | 11 +++++++++-- - 1 file changed, 9 insertions(+), 2 deletions(-) - -diff --git a/qtfs/qtfs/sb.c b/qtfs/qtfs/sb.c -index 5fd2c8f..aad153b 100644 ---- a/qtfs/qtfs/sb.c -+++ b/qtfs/qtfs/sb.c -@@ -1146,6 +1146,7 @@ int qtfs_getattr(const struct path *path, struct kstat *stat, u32 req_mask, unsi - struct qtfs_sock_var_s *pvar = qtfs_conn_get_param(); - struct qtreq_getattr *req; - struct qtrsp_getattr *rsp; -+ struct inode *inode = path->dentry->d_inode; - int ret; - - if (!pvar) { -@@ -1172,8 +1173,14 @@ int qtfs_getattr(const struct path *path, struct kstat *stat, u32 req_mask, unsi - return ret; - } - *stat = rsp->stat; -- qtfs_debug("qtfs getattr success:<%s> blksiz:%u size:%lld mode:%o ino:%llu pathino:%lu.\n", req->path, rsp->stat.blksize, -- rsp->stat.size, rsp->stat.mode, rsp->stat.ino, path->dentry->d_inode->i_ino); -+ qtfs_debug("qtfs getattr success:<%s> blksiz:%u size:%lld mode:%o ino:%llu pathino:%lu. %s\n", req->path, rsp->stat.blksize, -+ rsp->stat.size, rsp->stat.mode, rsp->stat.ino, inode->i_ino, rsp->stat.ino != inode->i_ino ? "delete current inode" : ""); -+ if (inode->i_ino != rsp->stat.ino || rsp->stat.mode != inode->i_mode) { -+ if (inode->i_nlink > 0){ -+ drop_nlink(inode); -+ } -+ d_invalidate(path->dentry); -+ } - qtfs_conn_put_param(pvar); - return 0; - } --- -2.33.0 - diff --git a/0004-add-uds-test-mode-in-engine-compile.patch b/0004-add-uds-test-mode-in-engine-compile.patch new file mode 100644 index 0000000000000000000000000000000000000000..7cff0d96665d81e1790584ff5aa3725ca199a5be --- /dev/null +++ b/0004-add-uds-test-mode-in-engine-compile.patch @@ -0,0 +1,24 @@ +From 5185a08ec742ee044c4efa7fa5e1ae9fb454f80f Mon Sep 17 00:00:00 2001 +From: liqiang +Date: Mon, 5 Jun 2023 20:53:39 +0800 +Subject: add uds test mode in engine compile + +Signed-off-by: liqiang +--- + qtfs/qtfs_server/Makefile | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/qtfs/qtfs_server/Makefile b/qtfs/qtfs_server/Makefile +index 0a8ed39..d00ce66 100644 +--- a/qtfs/qtfs_server/Makefile ++++ b/qtfs/qtfs_server/Makefile +@@ -1,5 +1,6 @@ + ifdef QTFS_TEST_MODE + ccflags-y += -I$(src)/../ -I$(src) -I$(src)/../ipc/ -I$(src)/../include/ -DQTFS_SERVER -DQTFS_TEST_MODE ++CFLAGS += -DUDS_TEST_MODE + else + ccflags-y += -I$(src)/../ -I$(src) -I$(src)/../ipc/ -I$(src)/../include/ -DQTFS_SERVER + endif +-- +2.33.0 + diff --git a/0005-Add-whitelist-of-qtfs.patch b/0005-Add-whitelist-of-qtfs.patch deleted file mode 100644 index 26e1c680eca6d45cf676f788160007ff0211cf9c..0000000000000000000000000000000000000000 --- a/0005-Add-whitelist-of-qtfs.patch +++ /dev/null @@ -1,896 +0,0 @@ -From 2052c2d81abe204e557b7b7d15be623caf26d7f7 Mon Sep 17 00:00:00 2001 -From: yangxin <245051644@qq.com> -Date: Fri, 10 Feb 2023 16:37:27 +0800 -Subject: [PATCH 1/5] Add whitelist of qtfs. - -Signed-off-by: yangxin <245051644@qq.com> ---- - qtfs/comm.h | 31 ++++ - qtfs/misc.c | 2 - - qtfs/qtfs/Makefile | 2 +- - qtfs/qtfs/qtfs-mod.h | 1 - - qtfs/qtfs/sb.c | 17 +- - qtfs/qtfs/syscall.c | 3 +- - qtfs/qtfs_server/Makefile | 4 +- - qtfs/qtfs_server/fsops.c | 145 ++++++++++++++---- - qtfs/qtfs_server/qtfs-server.c | 35 ++++- - qtfs/qtfs_server/qtfs-server.h | 1 + - qtfs/qtfs_server/user_engine.c | 51 +++++- - qtfs/req.h | 36 ++--- - .../whitelist/libvirt/qtfs_whitelist | 35 +++++ - 13 files changed, 286 insertions(+), 77 deletions(-) - create mode 100644 usecases/transparent-offload/whitelist/libvirt/qtfs_whitelist - -diff --git a/qtfs/comm.h b/qtfs/comm.h -index d639c19..901552c 100644 ---- a/qtfs/comm.h -+++ b/qtfs/comm.h -@@ -13,6 +13,7 @@ enum { - _QTFS_IOCTL_EXIT, - - _QTFS_IOCTL_ALLINFO, -+ _QTFS_IOCTL_WHITELIST, - _QTFS_IOCTL_CLEARALL, - - _QTFS_IOCTL_LOG_LEVEL, -@@ -26,6 +27,7 @@ enum { - #define QTFS_IOCTL_EPOLL_THREAD_RUN _IO(QTFS_IOCTL_MAGIC, _QTFS_IOCTL_EPOLL_THREAD_RUN) - #define QTFS_IOCTL_EXIT _IO(QTFS_IOCTL_MAGIC, _QTFS_IOCTL_EXIT) - #define QTFS_IOCTL_ALLINFO _IO(QTFS_IOCTL_MAGIC, _QTFS_IOCTL_ALLINFO) -+#define QTFS_IOCTL_WHITELIST _IO(QTFS_IOCTL_MAGIC, _QTFS_IOCTL_WHITELIST) - #define QTFS_IOCTL_CLEARALL _IO(QTFS_IOCTL_MAGIC, _QTFS_IOCTL_CLEARALL) - #define QTFS_IOCTL_LOGLEVEL _IO(QTFS_IOCTL_MAGIC, _QTFS_IOCTL_LOG_LEVEL) - #define QTFS_IOCTL_EPOLL_SUPPORT _IO(QTFS_IOCTL_MAGIC, _QTFS_IOCTL_EPOLL_SUPPORT) -@@ -42,6 +44,35 @@ struct qtfs_server_userp_s { - void *userp2; - }; - -+ -+enum { -+ QTFS_WHITELIST_OPEN, -+ QTFS_WHITELIST_WRITE, -+ QTFS_WHITELIST_READ, -+ QTFS_WHITELIST_READDIR, -+ QTFS_WHITELIST_MKDIR, -+ QTFS_WHITELIST_RMDIR, -+ QTFS_WHITELIST_CREATE, -+ QTFS_WHITELIST_UNLINK, -+ QTFS_WHITELIST_RENAME, -+ QTFS_WHITELIST_SETATTR, -+ QTFS_WHITELIST_SETXATTR, -+ QTFS_WHITELIST_MOUNT, -+ QTFS_WHITELIST_MAX, -+}; -+ -+ -+struct wl_item { -+ int len; -+ char path[4096]; -+}; -+ -+struct whitelist { -+ int len; -+ int type; -+ struct wl_item wl[0]; -+}; -+ - struct qtfs_thread_init_s { - int thread_nums; - struct qtfs_server_userp_s *userp; -diff --git a/qtfs/misc.c b/qtfs/misc.c -index 90c8d36..98222bd 100644 ---- a/qtfs/misc.c -+++ b/qtfs/misc.c -@@ -61,7 +61,6 @@ void qtfs_req_size(void) - qtfs_diag_info->req_size[QTFS_REQ_MOUNT] = sizeof(struct qtreq_mount); - qtfs_diag_info->req_size[QTFS_REQ_OPEN] = sizeof(struct qtreq_open); - qtfs_diag_info->req_size[QTFS_REQ_CLOSE] = sizeof(struct qtreq_close); -- qtfs_diag_info->req_size[QTFS_REQ_READ] = sizeof(struct qtreq_read); - qtfs_diag_info->req_size[QTFS_REQ_READITER] = sizeof(struct qtreq_readiter); - qtfs_diag_info->req_size[QTFS_REQ_WRITE] = sizeof(struct qtreq_write); - qtfs_diag_info->req_size[QTFS_REQ_LOOKUP] = sizeof(struct qtreq_lookup); -@@ -92,7 +91,6 @@ void qtfs_req_size(void) - qtfs_diag_info->rsp_size[QTFS_REQ_MOUNT] = sizeof(struct qtrsp_mount); - qtfs_diag_info->rsp_size[QTFS_REQ_OPEN] = sizeof(struct qtrsp_open); - qtfs_diag_info->rsp_size[QTFS_REQ_CLOSE] = sizeof(struct qtrsp_close); -- qtfs_diag_info->rsp_size[QTFS_REQ_READ] = sizeof(struct qtrsp_read); - qtfs_diag_info->rsp_size[QTFS_REQ_READITER] = sizeof(struct qtrsp_readiter); - qtfs_diag_info->rsp_size[QTFS_REQ_WRITE] = sizeof(struct qtrsp_write); - qtfs_diag_info->rsp_size[QTFS_REQ_LOOKUP] = sizeof(struct qtrsp_lookup); -diff --git a/qtfs/qtfs/Makefile b/qtfs/qtfs/Makefile -index f3c6014..f03ec52 100644 ---- a/qtfs/qtfs/Makefile -+++ b/qtfs/qtfs/Makefile -@@ -11,4 +11,4 @@ qtfs: - - clean: - make -C $(KBUILD) M=$(PWD) clean -- rm -rf ../*.o -+ rm -rf ../*.o ../.*.o.cmd -diff --git a/qtfs/qtfs/qtfs-mod.h b/qtfs/qtfs/qtfs-mod.h -index 5a30868..6ba7a4d 100644 ---- a/qtfs/qtfs/qtfs-mod.h -+++ b/qtfs/qtfs/qtfs-mod.h -@@ -35,7 +35,6 @@ extern struct kmem_cache *qtfs_inode_priv_cache; - - struct private_data { - int fd; -- unsigned long long file; - }; - - struct qtfs_inode_priv { -diff --git a/qtfs/qtfs/sb.c b/qtfs/qtfs/sb.c -index 06ce402..9374cfb 100644 ---- a/qtfs/qtfs/sb.c -+++ b/qtfs/qtfs/sb.c -@@ -196,7 +196,6 @@ int qtfs_open(struct inode *inode, struct file *file) - return err; - } - qtfs_info("qtfs open:%s success, f_mode:%o flag:%x, fd:%d", req->path, file->f_mode, file->f_flags, rsp->fd); -- data->file = rsp->file; - data->fd = rsp->fd; - WARN_ON(file->private_data); - file->private_data = data; -@@ -287,9 +286,9 @@ ssize_t qtfs_readiter(struct kiocb *kio, struct iov_iter *iov) - return -ENOMEM; - } - -- req->file = private->file; -- if (req->file <= 0) { -- qtfs_err("qtfs_readiter: invalid file(0x%llx)", req->file); -+ req->fd = private->fd; -+ if (req->fd <= 0) { -+ qtfs_err("qtfs_readiter: invalid file(0x%llx)", req->fd); - qtfs_conn_put_param(pvar); - return -EINVAL; - } -@@ -359,9 +358,9 @@ ssize_t qtfs_writeiter(struct kiocb *kio, struct iov_iter *iov) - return -ENOMEM; - } - -- req->d.file = private->file; -- if (req->d.file < 0) { -- qtfs_err("qtfs_write: invalid file(0x%llx)", req->d.file); -+ req->d.fd = private->fd; -+ if (req->d.fd < 0) { -+ qtfs_err("qtfs_write: invalid file(0x%llx)", req->d.fd); - qtfs_conn_put_param(pvar); - return -EINVAL; - } -@@ -617,7 +616,7 @@ qtfsfifo_poll(struct file *filp, poll_table *wait) - - p = &priv->readq.head; - -- if (IS_ERR((void *)fpriv->file) || (void *)fpriv->file == NULL) { -+ if (fpriv->fd < 0) { - qtfs_err("fifo poll priv file invalid."); - return 0; - } -@@ -627,7 +626,7 @@ qtfsfifo_poll(struct file *filp, poll_table *wait) - return 0; - } - req = qtfs_sock_msg_buf(pvar, QTFS_SEND); -- req->file = fpriv->file; -+ req->fd = fpriv->fd; - rsp = qtfs_remote_run(pvar, QTFS_REQ_FIFOPOLL, sizeof(struct qtreq_poll)); - if (IS_ERR(rsp) || rsp == NULL) { - qtfs_conn_put_param(pvar); -diff --git a/qtfs/qtfs/syscall.c b/qtfs/qtfs/syscall.c -index 85cfbbe..2912f48 100644 ---- a/qtfs/qtfs/syscall.c -+++ b/qtfs/qtfs/syscall.c -@@ -110,7 +110,6 @@ static void do_epoll_ctl_remote(int op, struct epoll_event __user *event, struct - } - req = qtfs_sock_msg_buf(pvar, QTFS_SEND); - req->fd = priv->fd; -- req->file = priv->file; - req->op = op; - if (ep_op_has_event(op) && copy_from_user(&tmp, event, sizeof(struct epoll_event))) { - qtfs_err("qtfs do epoll ctl remote copy from user failed."); -@@ -131,7 +130,7 @@ static void do_epoll_ctl_remote(int op, struct epoll_event __user *event, struct - } else { - qtinfo_cntinc(QTINF_EPOLL_DELFDS); - } -- qtfs_info("qtfs do epoll ctl remote success, fd:%d file:%lx.", req->fd, (unsigned long)req->file); -+ qtfs_info("qtfs do epoll ctl remote success, fd:%d.", req->fd); - qtfs_conn_put_param(pvar); - return; - } -diff --git a/qtfs/qtfs_server/Makefile b/qtfs/qtfs_server/Makefile -index c1c5ef6..9c6bcd5 100644 ---- a/qtfs/qtfs_server/Makefile -+++ b/qtfs/qtfs_server/Makefile -@@ -10,9 +10,9 @@ qtfs_server: - make -C $(KBUILD) M=$(PWD) modules - - engine: -- gcc -O2 -o engine user_engine.c -lpthread -I../ -DQTFS_SERVER -+ gcc -O2 -o engine user_engine.c -lpthread -lglib-2.0 -I../ -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -DQTFS_SERVER - - clean: - make -C $(KBUILD) M=$(PWD) clean - rm -rf engine -- rm -rf ../*.o -+ rm -rf ../*.o ../.*.o.cmd -diff --git a/qtfs/qtfs_server/fsops.c b/qtfs/qtfs_server/fsops.c -index 48ec7ab..d00db6d 100644 ---- a/qtfs/qtfs_server/fsops.c -+++ b/qtfs/qtfs_server/fsops.c -@@ -23,6 +23,21 @@ - #define RSP(arg) (arg->out) - #define USERP(arg) (arg->userp) - -+bool in_white_list(char *path, int type) -+{ -+ if (!whitelist[type]) { -+ return true; -+ } -+ int i, in_wl = -1; -+ for (i = 0; i < whitelist[type]->len; i++) { -+ if (!strncmp(path, whitelist[type]->wl[i].path, whitelist[type]->wl[i].len)){ -+ in_wl = i; -+ break; -+ } -+ } -+ return in_wl != -1; -+} -+ - static inline void qtfs_inode_info_fill(struct inode_info *ii, struct inode *inode) - { - ii->mode = inode->i_mode; -@@ -55,7 +70,6 @@ static int handle_ioctl(struct qtserver_arg *arg) - struct qtreq_ioctl *req = (struct qtreq_ioctl *)REQ(arg); - struct qtrsp_ioctl *rsp = (struct qtrsp_ioctl *)RSP(arg); - struct qtfs_server_userp_s *userp = (struct qtfs_server_userp_s *)USERP(arg); -- - file = filp_open(req->path, O_RDONLY, 0); - if (err_ptr(file)) { - qtfs_err("handle ioctl error, path:<%s> failed.\n", req->path); -@@ -188,9 +202,13 @@ static int handle_statfs(struct qtserver_arg *arg) - static int handle_mount(struct qtserver_arg *arg) - { - struct path path; -- int ret; -+ int ret, i, in_wl = -1; - struct qtreq_mount *req = (struct qtreq_mount *)REQ(arg); - struct qtrsp_mount *rsp = (struct qtrsp_mount *)RSP(arg); -+ if (!in_white_list(req->path, QTFS_WHITELIST_MOUNT)) { -+ rsp->ret = QTFS_ERR; -+ return sizeof(rsp->ret); -+ } - - ret = kern_path(req->path, LOOKUP_DIRECTORY, &path); - if (ret) { -@@ -208,11 +226,15 @@ int handle_open(struct qtserver_arg *arg) - { - int fd; - int ret; -- struct fd f; -- struct file *file = NULL; - struct qtreq_open *req = (struct qtreq_open *)REQ(arg); - struct qtrsp_open *rsp = (struct qtrsp_open *)RSP(arg); - struct qtfs_server_userp_s *userp = (struct qtfs_server_userp_s *)USERP(arg); -+ if (!in_white_list(req->path, QTFS_WHITELIST_OPEN)) { -+ qtfs_err("handle open path:%s not permited", req->path); -+ rsp->ret = QTFS_ERR; -+ rsp->fd = -EACCES; -+ return sizeof(struct qtrsp_open); -+ } - - ret = copy_to_user(userp->userp, req->path, strlen(req->path)+1); - if (ret) { -@@ -235,26 +257,11 @@ int handle_open(struct qtserver_arg *arg) - } - rsp->ret = QTFS_ERR; - rsp->fd = fd; -- rsp->file = 0; - return sizeof(struct qtrsp_open); - } - -- f = fdget(fd); -- file = f.file; -- if (err_ptr(file)) { -- rsp->ret = QTFS_ERR; -- rsp->fd = PTR_ERR(file); -- // must close_fd(fd)? -- WARN_ON(1); -- qtfs_err("handle open get file pointer of <<%s>> error, fd:%d file err:%d.", req->path, fd, rsp->fd); -- // XXX: fileclose here? -- } else { -- rsp->ret = QTFS_OK; -- rsp->file = (__u64)file; -- rsp->fd = fd; -- } -- qtfs_info("handle open file :%s fd:%d filep:%lx.", req->path, fd, (unsigned long)rsp->file); -- fdput(f); -+ rsp->ret = QTFS_OK; -+ rsp->fd = fd; - return sizeof(struct qtrsp_open); - } - -@@ -279,18 +286,30 @@ int handle_close(struct qtserver_arg *arg) - static int handle_readiter(struct qtserver_arg *arg) - { - struct file *file = NULL; -+ char *pathbuf, *fullname; - struct qtreq_readiter *req = (struct qtreq_readiter *)REQ(arg); - struct qtrsp_readiter *rsp = (struct qtrsp_readiter *)RSP(arg); - struct qtfs_server_userp_s *userp = (struct qtfs_server_userp_s *)USERP(arg); - size_t maxlen = (req->len >= sizeof(rsp->readbuf)) ? (sizeof(rsp->readbuf) - 1) : req->len; - -- file = (struct file *)req->file; -+ file = fget(req->fd); -+ pathbuf = __getname(); -+ fullname = file_path(file, pathbuf, PATH_MAX); -+ if (!in_white_list(fullname, QTFS_WHITELIST_READ)) { -+ qtfs_err("%s not in whitelist.\n", fullname); -+ __putname(pathbuf); -+ rsp->d.ret = QTFS_ERR; -+ rsp->d.len = 0; -+ rsp->d.errno = -ENOENT; -+ goto end; -+ } -+ __putname(pathbuf); - if (err_ptr(file)) { - qtfs_err("handle readiter error, open failed, file:%p.\n", file); - rsp->d.ret = QTFS_ERR; - rsp->d.len = 0; - rsp->d.errno = -ENOENT; -- return sizeof(struct qtrsp_readiter) - sizeof(rsp->readbuf) + rsp->d.len; -+ goto end; - } - if (file->f_op->read) { - int idx = 0; -@@ -326,23 +345,35 @@ static int handle_readiter(struct qtserver_arg *arg) - - qtfs_info("handle readiter file:<%s>, len:%lu, rsplen:%ld, pos:%lld, ret:%d errno:%d.\n", - file->f_path.dentry->d_iname, req->len, rsp->d.len, req->pos, rsp->d.ret, rsp->d.errno); -+end: -+ fput(file); - return sizeof(struct qtrsp_readiter) - sizeof(rsp->readbuf) + rsp->d.len; - } - - static int handle_write(struct qtserver_arg *arg) - { - struct file *file = NULL; -+ char *pathbuf, *fullname; - struct qtreq_write *req = (struct qtreq_write *)REQ(arg); - struct qtrsp_write *rsp = (struct qtrsp_write *)RSP(arg); - struct qtfs_server_userp_s *userp = (struct qtfs_server_userp_s *)USERP(arg); - int idx = 0, leftlen = 0, ret = 0, len = 0; - -- file = (struct file *)req->d.file; -+ file = fget(req->d.fd); -+ pathbuf = __getname(); -+ fullname = file_path(file, pathbuf, PATH_MAX); -+ if (!in_white_list(fullname, QTFS_WHITELIST_WRITE)) { -+ kfree(pathbuf); -+ rsp->ret = QTFS_ERR; -+ rsp->len = 0; -+ goto end; -+ } -+ __putname(pathbuf); - if (err_ptr(file)) { - qtfs_err("qtfs handle write error, filp:<%p> open failed.\n", file); - rsp->ret = QTFS_ERR; - rsp->len = 0; -- return sizeof(struct qtrsp_write); -+ goto end; - } - - file->f_mode = req->d.mode; -@@ -372,6 +403,8 @@ static int handle_write(struct qtserver_arg *arg) - rsp->ret = (rsp->len <= 0) ? QTFS_ERR : QTFS_OK; - qtfs_info("handle write file<%s> %s, write len:%ld pos:%lld mode:%o flags:%x.", file->f_path.dentry->d_iname, - (rsp->ret == QTFS_ERR) ? "failed" : "succeded", rsp->len, req->d.pos, file->f_mode, file->f_flags); -+end: -+ fput(file); - return sizeof(struct qtrsp_write); - } - -@@ -438,6 +471,12 @@ static int handle_readdir(struct qtserver_arg *arg) - .dir = (struct qtfs_dirent64 *)rsp->dirent, - .vldcnt = 0, - }; -+ -+ if (!in_white_list(req->path, QTFS_WHITELIST_READDIR)) { -+ rsp->d.ret = QTFS_ERR; -+ rsp->d.vldcnt = 0; -+ return sizeof(struct qtrsp_readdir) - sizeof(rsp->dirent); -+ } - file = filp_open(req->path, O_RDONLY|O_NONBLOCK|O_DIRECTORY, 0); - if (err_ptr(file)) { - qtfs_err("handle readdir error, filp:<%s> open failed.\n", req->path); -@@ -466,7 +505,11 @@ static int handle_mkdir(struct qtserver_arg *arg) - struct inode *inode; - struct path path; - int ret; -- -+ -+ if (!in_white_list(req->path, QTFS_WHITELIST_MKDIR)) { -+ rsp->errno = -EFAULT; -+ goto err; -+ } - if (copy_to_user(userp->userp, req->path, strlen(req->path) + 1)) { - qtfs_err("handle mkdir copy to userp failed.\n"); - rsp->errno = -EFAULT; -@@ -499,7 +542,11 @@ static int handle_rmdir(struct qtserver_arg *arg) - struct qtreq_rmdir *req = (struct qtreq_rmdir *)REQ(arg); - struct qtrsp_rmdir *rsp = (struct qtrsp_rmdir *)RSP(arg); - struct qtfs_server_userp_s *userp = (struct qtfs_server_userp_s *)USERP(arg); -- -+ -+ if (!in_white_list(req->path, QTFS_WHITELIST_RMDIR)) { -+ rsp->errno = -EFAULT; -+ goto err; -+ } - if (copy_to_user(userp->userp, req->path, strlen(req->path) + 1)) { - qtfs_err("handle rmdir copy to userp failed.\n"); - rsp->errno = -EFAULT; -@@ -558,6 +605,12 @@ static int handle_setattr(struct qtserver_arg *arg) - struct inode *inode = NULL; - struct path path; - int ret; -+ -+ if (!in_white_list(req->path, QTFS_WHITELIST_SETATTR)) { -+ rsp->ret = QTFS_ERR; -+ rsp->errno = -ENOENT; -+ return sizeof(struct qtrsp_setattr); -+ } - - ret = kern_path(req->path, 0, &path); - if (ret) { -@@ -610,6 +663,12 @@ int handle_icreate(struct qtserver_arg *arg) - struct inode *inode; - struct qtreq_icreate *req = (struct qtreq_icreate *)REQ(arg); - struct qtrsp_icreate *rsp = (struct qtrsp_icreate *)RSP(arg); -+ -+ if (!in_white_list(req->path, QTFS_WHITELIST_CREATE)) { -+ rsp->ret = QTFS_ERR; -+ rsp->errno = -ENOENT; -+ return sizeof(struct qtrsp_icreate); -+ } - - file = filp_open(req->path, O_CREAT, req->mode); - if (err_ptr(file)) { -@@ -635,6 +694,12 @@ static int handle_mknod(struct qtserver_arg *arg) - struct path path; - int error; - unsigned int flags = LOOKUP_DIRECTORY; -+ -+ if (!in_white_list(req->path, QTFS_WHITELIST_CREATE)) { -+ rsp->ret = QTFS_ERR; -+ rsp->errno = -ENOENT; -+ return sizeof(struct qtrsp_mknod); -+ } - - retry: - dent = kern_path_create(AT_FDCWD, req->path, &path, flags); -@@ -668,6 +733,11 @@ int handle_unlink(struct qtserver_arg *arg) - { - struct qtreq_unlink *req = (struct qtreq_unlink *)REQ(arg); - struct qtrsp_unlink *rsp = (struct qtrsp_unlink *)RSP(arg); -+ -+ if (!in_white_list(req->path, QTFS_WHITELIST_UNLINK)) { -+ rsp->errno = -ENOENT; -+ return sizeof(struct qtrsp_unlink); -+ } - - rsp->errno = qtfs_kern_syms.do_unlinkat(AT_FDCWD, qtfs_kern_syms.getname_kernel(req->path)); - if (rsp->errno < 0) { -@@ -770,7 +840,11 @@ int handle_rename(struct qtserver_arg *arg) - struct qtreq_rename *req = (struct qtreq_rename *)REQ(arg); - struct qtrsp_rename *rsp = (struct qtrsp_rename *)RSP(arg); - struct qtfs_server_userp_s *userp = (struct qtfs_server_userp_s *)USERP(arg); -- -+ -+ if (!in_white_list(req->path, QTFS_WHITELIST_RENAME)) { -+ rsp->errno = -ENOENT; -+ goto err_handle; -+ } - if (copy_to_user(userp->userp, req->path, strlen(req->path) + 1) || - copy_to_user(userp->userp2, &req->path[req->d.oldlen], strlen(&req->path[req->d.oldlen]) + 1)) { - qtfs_err("handle rename copy to userp failed.\n"); -@@ -831,6 +905,12 @@ int handle_xattrset(struct qtserver_arg *arg) - struct path path; - int ret = 0; - -+ if (!in_white_list(req->buf, QTFS_WHITELIST_SETXATTR)) { -+ rsp->errno = -ENOENT; -+ rsp->ret = QTFS_ERR; -+ goto err_handle; -+ } -+ - ret = kern_path(req->buf, 0, &path); - if (ret) { - qtfs_err("handle xattrset path error, file:%s.\n", req->buf); -@@ -997,7 +1077,7 @@ int handle_fifopoll(struct qtserver_arg *arg) - struct poll_wqueues table; - poll_table *pt; - -- filp = (struct file *)req->file; -+ filp = fget(req->fd); - inode = filp->f_inode; - if (!S_ISFIFO(inode->i_mode)) { - msleep(1); -@@ -1011,6 +1091,7 @@ int handle_fifopoll(struct qtserver_arg *arg) - if (pipe == NULL) { - qtfs_err("file :%s pipe data is NULL.", filp->f_path.dentry->d_iname); - rsp->ret = QTFS_ERR; -+ fput(filp); - return sizeof(struct qtrsp_poll); - } - head = READ_ONCE(pipe->head); -@@ -1035,6 +1116,7 @@ end: - - qtfs_info("handle fifo poll f_mode:%o: %s get poll mask 0x%x poll:%lx\n", - filp->f_mode, filp->f_path.dentry->d_iname, rsp->mask, (unsigned long)filp->f_op->poll); -+ fput(filp); - return sizeof(struct qtrsp_poll); - } - -@@ -1055,8 +1137,8 @@ int handle_epollctl(struct qtserver_arg *arg) - } - qtinfo_cntinc((req->op == EPOLL_CTL_ADD) ? QTINF_EPOLL_ADDFDS : QTINF_EPOLL_DELFDS); - rsp->ret = QTFS_OK; -- qtfs_info("handle do epoll ctl success, fd:%d file:%lx op:%x data:%lx poll_t:%x.", -- req->fd, (unsigned long)req->file, req->op, req->event.data, (unsigned)req->event.events); -+ qtfs_info("handle do epoll ctl success, fd:%d op:%x data:%lx poll_t:%x.", -+ req->fd, req->op, req->event.data, (unsigned)req->event.events); - - return sizeof(struct qtrsp_epollctl); - } -@@ -1197,3 +1279,4 @@ int qtfs_sock_server_run(struct qtfs_sock_var_s *pvar) - qtfs_sock_msg_clear(pvar); - return (ret < 0) ? QTERROR : QTOK; - } -+ -diff --git a/qtfs/qtfs_server/qtfs-server.c b/qtfs/qtfs_server/qtfs-server.c -index bcd60b7..b0b8ab0 100644 ---- a/qtfs/qtfs_server/qtfs-server.c -+++ b/qtfs/qtfs_server/qtfs-server.c -@@ -28,6 +28,8 @@ struct qtfs_server_epoll_s qtfs_epoll = { - .events = NULL, - }; - -+struct whitelist* whitelist[QTFS_WHITELIST_MAX]; -+ - long qtfs_server_epoll_thread(struct qtfs_sock_var_s *pvar) - { - int n; -@@ -140,9 +142,10 @@ long qtfs_server_epoll_init(void) - - long qtfs_server_misc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) - { -- int i; -+ int i, len; - long ret = 0; - struct qtfs_sock_var_s *pvar; -+ struct whitelist *tmp; - struct qtfs_thread_init_s init_userp; - switch (cmd) { - case QTFS_IOCTL_THREAD_INIT: -@@ -216,6 +219,26 @@ long qtfs_server_misc_ioctl(struct file *file, unsigned int cmd, unsigned long a - case QTFS_IOCTL_LOGLEVEL: - ret = qtfs_misc_ioctl(file, cmd, arg); - break; -+ case QTFS_IOCTL_WHITELIST: -+ if (copy_from_user(&len, (void __user *)arg, sizeof(int))) { -+ qtfs_err("qtfs ioctl white init copy from user failed."); -+ return QTERROR; -+ } -+ tmp = (struct whitelist *)kmalloc(sizeof(struct whitelist) + sizeof(struct wl_item) * len, GFP_KERNEL); -+ -+ if (copy_from_user(tmp, (void __user *)arg, sizeof(struct whitelist) + sizeof(struct wl_item) * len)) { -+ qtfs_err("qtfs ioctl white init copy from user failed."); -+ return QTERROR; -+ } -+ -+ if (whitelist[tmp->type] != NULL) { -+ kfree(whitelist[tmp->type]); -+ } -+ whitelist[tmp->type] = tmp; -+ for (i = 0; i < whitelist[tmp->type]->len; i++) { -+ qtfs_err("init %d list:%d %s", tmp->type, i, whitelist[tmp->type]->wl[i].path); -+ } -+ break; - default: - qtfs_err("qtfs misc ioctl unknown cmd:%u.", cmd); - break; -@@ -226,7 +249,11 @@ long qtfs_server_misc_ioctl(struct file *file, unsigned int cmd, unsigned long a - - static int __init qtfs_server_init(void) - { -+ int i; - qtfs_log_init(qtfs_log_level); -+ for (i = 0; i < QTFS_WHITELIST_MAX; i++) { -+ whitelist[i] = NULL; -+ } - qtfs_diag_info = (struct qtinfo *)kmalloc(sizeof(struct qtinfo), GFP_KERNEL); - if (qtfs_diag_info == NULL) - qtfs_err("kmalloc qtfs diag info failed."); -@@ -246,6 +273,7 @@ static int __init qtfs_server_init(void) - - static void __exit qtfs_server_exit(void) - { -+ int i; - qtfs_mod_exiting = true; - qtfs_server_thread_run = 0; - -@@ -269,6 +297,11 @@ static void __exit qtfs_server_exit(void) - kfree(qtfs_userps); - qtfs_userps = NULL; - } -+ for (i = 0; i < QTFS_WHITELIST_MAX; i++) { -+ if (whitelist[i] != NULL) { -+ kfree(whitelist[i]); -+ } -+ } - qtfs_misc_destroy(); - qtfs_info("qtfs server exit done.\n"); - return; -diff --git a/qtfs/qtfs_server/qtfs-server.h b/qtfs/qtfs_server/qtfs-server.h -index 8bcadf6..d10742a 100644 ---- a/qtfs/qtfs_server/qtfs-server.h -+++ b/qtfs/qtfs_server/qtfs-server.h -@@ -4,6 +4,7 @@ - extern int qtfs_server_thread_run; - extern struct qtfs_server_epoll_s qtfs_epoll; - extern int qtfs_mod_exiting; -+extern struct whitelist* whitelist[QTFS_WHITELIST_MAX]; - - struct qtserver_arg { - char *data; -diff --git a/qtfs/qtfs_server/user_engine.c b/qtfs/qtfs_server/user_engine.c -index a062b63..547935c 100644 ---- a/qtfs/qtfs_server/user_engine.c -+++ b/qtfs/qtfs_server/user_engine.c -@@ -9,11 +9,14 @@ - #include - #include - #include -+#include - - #include - - #include "comm.h" - -+char wl_type_str[QTFS_WHITELIST_MAX][10] = {"Open", "Write", "Read", "Readdir", "Mkdir", "Rmdir", "Create", "Unlink", "Rename", "Setattr", "Setxattr", "Mount"}; -+ - #define engine_out(info, ...) \ - do {\ - printf("[Engine::%s:%3d]"info"\n", __func__, __LINE__, ##__VA_ARGS__);\ -@@ -29,6 +32,10 @@ - printf("[ERROR:Engine::%s:%3d]"info"\n", __func__, __LINE__, ##__VA_ARGS__);\ - } while (0); - -+#define WHITELIST_FILE "/etc/qtfs/whitelist" -+ -+struct whitelist *whitelist[QTFS_WHITELIST_MAX]; -+ - struct engine_arg { - int psize; - int fd; -@@ -171,6 +178,46 @@ int qtfs_epoll_init(int fd) - return epfd; - } - -+static int qtfs_whitelist_transfer(int fd, GKeyFile *config, int type) -+{ -+ int64_t i, len; -+ char **items = g_key_file_get_string_list(config,wl_type_str[type],"Path",&len,NULL); -+ if (len == 0) { -+ engine_out("Can't find whitelist item %s", wl_type_str[type]); -+ return 0; -+ } -+ whitelist[type] = (struct whitelist *)malloc(sizeof(struct whitelist) + sizeof(struct wl_item) * len); -+ g_print("%s:\n", wl_type_str[type]); -+ whitelist[type]->len = len; -+ whitelist[type]->type = type; -+ for(i = 0; i < len;i++){ -+ printf("%s\n", items[i]); -+ whitelist[type]->wl[i].len = strlen(items[i]); -+ strcpy(whitelist[type]->wl[i].path, items[i]); -+ } -+ int ret = ioctl(fd, QTFS_IOCTL_WHITELIST, whitelist[type]); -+ free(items); -+ return ret; -+} -+ -+int qtfs_whitelist_init(int fd) -+{ -+ int ret, i; -+ GKeyFile *config = g_key_file_new(); -+ g_key_file_load_from_file(config, WHITELIST_FILE, G_KEY_FILE_KEEP_COMMENTS|G_KEY_FILE_KEEP_TRANSLATIONS, NULL); -+ for (i = 0; i < QTFS_WHITELIST_MAX; i++) { -+ ret = qtfs_whitelist_transfer(fd, config, i); -+ if (ret != 0) { -+ return ret; -+ } -+ } -+ g_key_file_free(config); -+ for (i = 0; i < QTFS_WHITELIST_MAX; i++) { -+ free(whitelist[i]); -+ } -+ return 0; -+} -+ - int main(int argc, char *argv[]) - { - if (argc != 3) { -@@ -192,6 +239,9 @@ int main(int argc, char *argv[]) - close(fd); - return -1; - } -+ if (qtfs_whitelist_init(fd)) { -+ goto end; -+ } - - umask(0); - -@@ -212,7 +262,6 @@ int main(int argc, char *argv[]) - engine_out("qtfs engine userp init failed."); - goto end; - } -- - struct engine_arg arg[QTFS_MAX_THREADS]; - for (int i = 0; i < thread_nums; i++) { - arg[i].psize = psize; -diff --git a/qtfs/req.h b/qtfs/req.h -index 0208667..3bcfa77 100644 ---- a/qtfs/req.h -+++ b/qtfs/req.h -@@ -12,29 +12,29 @@ enum qtreq_type { - QTFS_REQ_OPEN, - QTFS_REQ_CLOSE, - QTFS_REQ_READ, -- QTFS_REQ_READITER, //5 -+ QTFS_REQ_READITER, // 5 - QTFS_REQ_WRITE, - QTFS_REQ_LOOKUP, - QTFS_REQ_READDIR, - QTFS_REQ_MKDIR, -- QTFS_REQ_RMDIR, //10 -+ QTFS_REQ_RMDIR, // 10 - QTFS_REQ_GETATTR, - QTFS_REQ_SETATTR, - QTFS_REQ_ICREATE, - QTFS_REQ_MKNOD, -- QTFS_REQ_UNLINK, //15 -+ QTFS_REQ_UNLINK, // 15 - QTFS_REQ_SYMLINK, - QTFS_REQ_LINK, - QTFS_REQ_GETLINK, - QTFS_REQ_READLINK, -- QTFS_REQ_RENAME, //20 -+ QTFS_REQ_RENAME, // 20 - - QTFS_REQ_XATTRLIST, - QTFS_REQ_XATTRGET, - QTFS_REQ_XATTRSET, - - QTFS_REQ_SYSMOUNT, -- QTFS_REQ_SYSUMOUNT, //25 -+ QTFS_REQ_SYSUMOUNT, // 25 - QTFS_REQ_FIFOPOLL, - - QTFS_REQ_STATFS, -@@ -117,11 +117,11 @@ static inline void qtfs_nbytes_print(unsigned char *buf, int bytes) - #define QTFS_SEND_SIZE(stru, tailstr) sizeof(stru) - sizeof(tailstr) + strlen(tailstr) + 1 - - struct qtreq { -- unsigned int type; // operation type -+ unsigned int type; // operation type - unsigned int err; - unsigned long seq_num; // check code - size_t len; -- char data[QTFS_REQ_MAX_LEN]; // operation's private data -+ char data[QTFS_REQ_MAX_LEN]; // operation's private data - }; - - #define QTFS_MSG_LEN sizeof(struct qtreq) -@@ -169,7 +169,6 @@ struct qtreq_open { - }; - - struct qtrsp_open { -- __u64 file; - int fd; - int ret; - }; -@@ -182,25 +181,10 @@ struct qtrsp_close { - int ret; - }; - --struct qtreq_read { -- size_t len; -- long long pos; -- __u64 file; --}; -- --struct qtrsp_read { -- struct qtrsp_read_len { -- int ret; -- ssize_t len; -- int errno; -- } d; -- char readbuf[QTFS_TAIL_LEN(struct qtrsp_read_len)]; --}; -- - struct qtreq_readiter { - size_t len; - long long pos; -- __u64 file; -+ int fd; - }; - - struct qtrsp_readiter { -@@ -216,7 +200,7 @@ struct qtreq_write { - struct qtreq_write_len { - int buflen; - long long pos; -- __u64 file; -+ int fd; - long long flags; - long long mode; - } d; -@@ -505,7 +489,6 @@ struct qtrsp_sysumount { - - struct qtreq_poll { - int fd; -- __u64 file; - int qproc; - }; - -@@ -516,7 +499,6 @@ struct qtrsp_poll { - - - struct qtreq_epollctl { -- __u64 file; - int fd; - int op; - struct qtreq_epoll_event event; -diff --git a/usecases/transparent-offload/whitelist/libvirt/qtfs_whitelist b/usecases/transparent-offload/whitelist/libvirt/qtfs_whitelist -new file mode 100644 -index 0000000..d6e14ae ---- /dev/null -+++ b/usecases/transparent-offload/whitelist/libvirt/qtfs_whitelist -@@ -0,0 +1,35 @@ -+[Open] -+Path=/proc/sys/kernel/sched_autogroup_enabled;/proc/sys/vm;/sys/bus/pci;/sys/devices/pic;/sys/devices/system/node;/sys/kernel/mm;/sys/fs/cgroup;/home/VMs;/sys/fs/cgroup;/var/lib/libvirt/qemu;/sys/devices/system/cpu/online;/sys/module/kvm;/proc;/sys -+ -+[Write] -+Path=/proc/sys/kernel/sched_autogroup_enabled;/proc/sys/vm;/sys/bus/pci;/sys/devices/pic;/sys/devices/system/node;/sys/kernel/mm;/sys/fs/cgroup;/home/VMs;/sys/fs/cgroup;/var/lib/libvirt/qemu -+ -+[Readiter] -+Path=/sys/module/kvm;/proc;/home/VMs;/sys/kernel/mm/transparent_hugepage;/sys/devices/system/cpu/online;/sys/devices/system/node;/sys/devices;/sys/firmware;/var/lib/libvirt/qemu;/sys/fs/cgroup -+ -+[Readdir] -+Path=/proc;/sys/bus;/sys/kernel/iommu_groups;/sys/kernel/mm/hugepages;/sys/class;/sys/bus;/sys/class;/sys/devices/system;/var/lib/libvirt;/sys/fs/cgroup;/root/test;/sys/devices/system/node;/dev/pts;/home/VMs -+ -+[Mkdir] -+Path=/var/lib/libvirt/qemu;/home/VMs;/sys/fs/cgroup -+ -+[Rmdir] -+Path=/var/lib/libvirt/qemu;/home/VMs;/sys/fs/cgroup -+ -+[Create] -+Path=/var/lib/libvirt/qemu;/home/VMs;/sys/fs/cgroup -+ -+[Unlink] -+Path=/var/lib/libvirt/qemu;/home/VMs;/sys/fs/cgroup -+ -+[Rename] -+Path=/var/lib/libvirt/qemu;/home/VMs;/sys/fs/cgroup -+ -+[Setattr] -+Path=/sys/bus/pci/drivers/pcieport/unbind;/sys/bus/pci/drivers_probe;/sys/devices/pci0000:00/0000:00:08.0/driver_override;/root/test;/var/lib/libvirt/qemu;/sys/fs/cgroup;/home/VMs -+ -+[Setxattr] -+Path=/sys/bus/pci/drivers/pcieport/unbind;/sys/bus/pci/drivers_probe;/sys/devices/pci0000:00/0000:00:08.0/driver_override;/root/test;/var/lib/libvirt/qemu;/sys/fs/cgroup;/home/VMs -+ -+[Mount] -+Path=/home/VMs;/var/lib/libvirt;/proc;/sys;/dev/pts;/dev/vfio -\ No newline at end of file --- -2.33.0 - diff --git a/0005-modify-qtfs_dentry_revalidate.patch b/0005-modify-qtfs_dentry_revalidate.patch new file mode 100644 index 0000000000000000000000000000000000000000..99c3731016252bd33318fc1c28b13409aa346f52 --- /dev/null +++ b/0005-modify-qtfs_dentry_revalidate.patch @@ -0,0 +1,69 @@ +From 607c1e329ac107087fdadca0c997d3e0f66b3b06 Mon Sep 17 00:00:00 2001 +From: yangxin <245051644@qq.com> +Date: Thu, 8 Jun 2023 06:54:09 +0000 +Subject: modify qtfs_dentry_revalidate + +Signed-off-by: yangxin <245051644@qq.com> +--- + qtfs/qtfs/sb.c | 32 ++++++++++++++++++++++---------- + 1 file changed, 22 insertions(+), 10 deletions(-) + +diff --git a/qtfs/qtfs/sb.c b/qtfs/qtfs/sb.c +index b6bb3d7..2038c55 100644 +--- a/qtfs/qtfs/sb.c ++++ b/qtfs/qtfs/sb.c +@@ -1510,29 +1510,41 @@ const struct xattr_handler *qtfs_xattr_handlers[] = { + int qtfs_dentry_revalidate(struct dentry *dentry, unsigned int flags) + { + struct qtfs_conn_var_s *pvar = NULL; +- struct qtreq_mount *req = NULL; +- struct qtrsp_mount *rsp = NULL; +- +- // 1 means valid; 0 means invalid +- if (dentry && dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) { ++ struct qtreq_getattr *req; ++ struct qtrsp_getattr *rsp; ++ struct inode *inode = dentry->d_inode; ++ if (dentry && dentry->d_inode) { + if (jiffies - dentry->d_time < 2000) + return 1; +- + pvar = qtfs_conn_get_param(); +- if (!pvar) ++ if (!pvar) { ++ qtfs_err("Failed to get qtfs sock var\n"); + return 0; ++ } + + req = pvar->conn_ops->get_conn_msg_buf(pvar, QTFS_SEND); + qtfs_fullname(req->path, dentry, PATH_MAX); +- rsp = qtfs_remote_run(pvar, QTFS_REQ_MOUNT, strlen(req->path)); +- if (IS_ERR_OR_NULL(rsp) || rsp->ret != QTFS_OK) { ++ req->request_mask = STATX_BASIC_STATS; ++ req->query_flags = 0; ++ ++ rsp = qtfs_remote_run(pvar, QTFS_REQ_GETATTR, QTFS_SEND_SIZE(struct qtreq_getattr, req->path)); ++ if (IS_ERR_OR_NULL(rsp)) { ++ qtfs_conn_put_param(pvar); ++ return 0; ++ } ++ if (rsp->ret) { + qtfs_conn_put_param(pvar); + return 0; + } + ++ if (!inode || inode->i_ino != rsp->stat.ino || inode->i_mode != rsp->stat.mode) { ++ if (inode->i_nlink > 0) ++ drop_nlink(inode); ++ qtfs_conn_put_param(pvar); ++ return 0; ++ } + qtfs_conn_put_param(pvar); + dentry->d_time = jiffies; +- return 1; + } + return 1; + } +-- +2.33.0 + diff --git a/0006-Fix-error-of-getxattr-and-listxattr.patch b/0006-Fix-error-of-getxattr-and-listxattr.patch deleted file mode 100644 index 913429ee11c66407ddabfea5c0a7c266711ece82..0000000000000000000000000000000000000000 --- a/0006-Fix-error-of-getxattr-and-listxattr.patch +++ /dev/null @@ -1,354 +0,0 @@ -From e9615d46a09a5dc92bf1d2ee408f0c7efd717503 Mon Sep 17 00:00:00 2001 -From: yangxin <245051644@qq.com> -Date: Fri, 10 Feb 2023 16:39:20 +0800 -Subject: [PATCH 2/5] Fix-error-of-getxattr-and-listxattr - -Signed-off-by: yangxin <245051644@qq.com> ---- - qtfs/conn.c | 4 --- - qtfs/qtfs/qtfs-mod.c | 2 +- - qtfs/qtfs/sb.c | 6 ++--- - qtfs/qtfs/xattr.c | 55 ++++++++++------------------------------ - qtfs/qtfs_server/fsops.c | 16 +++++++----- - qtfs/qtinfo/qtinfo.h | 10 ++++---- - qtfs/req.h | 4 +-- - 7 files changed, 34 insertions(+), 63 deletions(-) - -diff --git a/qtfs/conn.c b/qtfs/conn.c -index af11fbe..26930b1 100644 ---- a/qtfs/conn.c -+++ b/qtfs/conn.c -@@ -76,10 +76,6 @@ static int qtfs_conn_sockserver_init(struct qtfs_sock_var_s *pvar) - { - struct socket *sock; - int ret; -- struct sockaddr_in saddr; -- saddr.sin_family = AF_INET; -- saddr.sin_port = htons(pvar->port); -- saddr.sin_addr.s_addr = in_aton(pvar->addr); - - if (!QTCONN_IS_EPOLL_CONN(pvar) && qtfs_server_main_sock != NULL) { - qtfs_info("qtfs server main sock is %lx, valid or out-of-date?", (unsigned long)qtfs_server_main_sock); -diff --git a/qtfs/qtfs/qtfs-mod.c b/qtfs/qtfs/qtfs-mod.c -index 9ccf0ee..abd9443 100644 ---- a/qtfs/qtfs/qtfs-mod.c -+++ b/qtfs/qtfs/qtfs-mod.c -@@ -9,7 +9,7 @@ static struct file_system_type qtfs_fs_type = { - .owner = THIS_MODULE, - .name = QTFS_FSTYPE_NAME, - .mount = qtfs_fs_mount, -- .kill_sb = qtfs_kill_sb,//qtfs_kill_sb, -+ .kill_sb = qtfs_kill_sb, - }; - MODULE_ALIAS_FS("qtfs"); - -diff --git a/qtfs/qtfs/sb.c b/qtfs/qtfs/sb.c -index 9374cfb..7445fad 100644 ---- a/qtfs/qtfs/sb.c -+++ b/qtfs/qtfs/sb.c -@@ -18,7 +18,7 @@ - static struct inode_operations qtfs_inode_ops; - static struct inode_operations qtfs_symlink_inode_ops; - struct inode *qtfs_iget(struct super_block *sb, struct inode_info *ii); -- -+extern ssize_t qtfs_xattr_list(struct dentry *dentry, char *buffer, size_t buffer_size); - int qtfs_statfs(struct dentry *dentry, struct kstatfs *buf) - { - struct qtfs_sock_var_s *pvar = qtfs_conn_get_param(); -@@ -396,7 +396,6 @@ ssize_t qtfs_writeiter(struct kiocb *kio, struct iov_iter *iov) - leftlen -= wrbuflen; - } while (leftlen); - -- //if (qtfs_support_epoll(kio->ki_filp->f_inode->i_mode) || ) { - do { - struct inode *inode = kio->ki_filp->f_inode; - struct qtfs_inode_priv *priv = inode->i_private; -@@ -406,7 +405,6 @@ ssize_t qtfs_writeiter(struct kiocb *kio, struct iov_iter *iov) - wake_up_interruptible_poll(&priv->readq, EPOLLIN); - qtfs_err("writeiter file:%s char:<%s> wakup poll.", filp->f_path.dentry->d_iname, req->path_buf); - } -- //qtfs_info("qtfs write iter fifo %s sync poll.", filp->f_path.dentry->d_iname); - } while (0); - qtfs_info("qtfs write %s over, leftlen:%lu.", filp->f_path.dentry->d_iname, leftlen); - qtfs_conn_put_param(pvar); -@@ -1338,12 +1336,14 @@ static struct inode_operations qtfs_inode_ops = { - .getattr = qtfs_getattr, - .setattr = qtfs_setattr, - .rename = qtfs_rename, -+ .listxattr = qtfs_xattr_list, - }; - - static struct inode_operations qtfs_symlink_inode_ops = { - .get_link = qtfs_getlink, - .getattr = qtfs_getattr, - .setattr = qtfs_setattr, -+ .listxattr = qtfs_xattr_list, - }; - - const struct xattr_handler *qtfs_xattr_handlers[] = { -diff --git a/qtfs/qtfs/xattr.c b/qtfs/qtfs/xattr.c -index a0d394a..a2a605d 100644 ---- a/qtfs/qtfs/xattr.c -+++ b/qtfs/qtfs/xattr.c -@@ -6,69 +6,52 @@ - #include "req.h" - #include "log.h" - --static bool qtfs_xattr_list(struct dentry *dentry) -+ssize_t qtfs_xattr_list(struct dentry *dentry, char *buffer, size_t buffer_size) - { - struct qtreq_xattrlist *req; - struct qtrsp_xattrlist *rsp; - struct qtfs_sock_var_s *pvar = qtfs_conn_get_param(); -- bool ret; -+ ssize_t ret; - - if (!pvar) { - qtfs_err("qtfs_xattr_list Failed to get qtfs sock var"); -- return -EINVAL; -+ return 0; - } - - if (dentry == NULL) { - qtfs_err("qtfs_xattr_list dentry is NULL."); - qtfs_conn_put_param(pvar); -- return false; -+ return 0; - } - - req = qtfs_sock_msg_buf(pvar, QTFS_SEND); - if (qtfs_fullname(req->path, dentry) < 0) { - qtfs_err("qtfs fullname failed"); - qtfs_conn_put_param(pvar); -- return false; -+ return 0; - } -- -- rsp = qtfs_remote_run(pvar, QTFS_REQ_XATTRLIST, strlen(req->path) + 1); -+ req->buffer_size = buffer_size; -+ rsp = qtfs_remote_run(pvar, QTFS_REQ_XATTRLIST, QTFS_SEND_SIZE(struct qtreq_xattrlist, req->path)); - if (IS_ERR(rsp) || rsp == NULL) { - qtfs_err("qtfs_xattr_list remote run failed."); - qtfs_conn_put_param(pvar); -- return false; -+ return 0; - } - - if (rsp->d.ret == QTFS_ERR) { - qtfs_err("qtfs_xattr_list failed with ret:%d.", rsp->d.ret); -- ret = rsp->d.result; -+ ret = rsp->d.size; - qtfs_conn_put_param(pvar); - return ret; - } -- ret = rsp->d.result; -+ ret = rsp->d.size; -+ if (buffer != NULL) { -+ memcpy(buffer, rsp->name, buffer_size); -+ } - qtfs_conn_put_param(pvar); - return ret; - } - --static bool qtfs_xattr_user_list(struct dentry *dentry) --{ -- return qtfs_xattr_list(dentry); --} -- --static bool qtfs_xattr_trusted_list(struct dentry *dentry) --{ -- return qtfs_xattr_list(dentry); --} -- --static bool qtfs_xattr_security_list(struct dentry *dentry) --{ -- return qtfs_xattr_list(dentry); --} -- --static bool qtfs_xattr_hurd_list(struct dentry *dentry) --{ -- return qtfs_xattr_list(dentry); --} -- - static int qtfs_xattr_set(const struct xattr_handler *handler, - struct dentry *dentry, struct inode *inode, - const char *name, const void *value, -@@ -177,12 +160,6 @@ static int qtfs_xattr_get(const struct xattr_handler *handler, - qtfs_err("Failed to get qtfs sock var"); - return 0; - } -- /*if (buf == NULL || size <= 0) { -- qtfs_err("xattr get failed, buf:%lx size:%d name:%s dentry:%lx", -- (unsigned long)buf, size, (name == NULL) ? "NULL" : name, (unsigned long)dentry); -- qtfs_conn_put_param(pvar); -- return 0; -- }*/ - - if (dentry == NULL) { - qtfs_err("xattr get dentry is NULL."); -@@ -216,7 +193,7 @@ static int qtfs_xattr_get(const struct xattr_handler *handler, - qtfs_conn_put_param(pvar); - return PTR_ERR(rsp); - } -- if (rsp->d.ret == QTFS_ERR || rsp->d.size > req->d.size || leftlen < rsp->d.size) { -+ if (rsp->d.ret == QTFS_ERR || (size !=0 && (rsp->d.size > req->d.size || leftlen < rsp->d.size))) { - qtfs_err("ret:%d rsp size:%ld req size:%d leftlen:%lu", rsp->d.ret, rsp->d.size, - req->d.size, leftlen); - goto err_end; -@@ -239,28 +216,24 @@ err_end: - - const struct xattr_handler qtfs_xattr_user_handler = { - .prefix = XATTR_USER_PREFIX, -- .list = qtfs_xattr_user_list, - .get = qtfs_xattr_get, - .set = qtfs_xattr_user_set, - }; - - const struct xattr_handler qtfs_xattr_trusted_handler = { - .prefix = XATTR_TRUSTED_PREFIX, -- .list = qtfs_xattr_trusted_list, - .get = qtfs_xattr_get, - .set = qtfs_xattr_trusted_set, - }; - - const struct xattr_handler qtfs_xattr_security_handler = { - .prefix = XATTR_SECURITY_PREFIX, -- .list = qtfs_xattr_security_list, - .get = qtfs_xattr_get, - .set = qtfs_xattr_security_set, - }; - - const struct xattr_handler qtfs_xattr_hurd_handler = { - .prefix = XATTR_HURD_PREFIX, -- .list = qtfs_xattr_hurd_list, - .get = qtfs_xattr_get, - .set = qtfs_xattr_hurd_set, - }; -diff --git a/qtfs/qtfs_server/fsops.c b/qtfs/qtfs_server/fsops.c -index d00db6d..61e8895 100644 ---- a/qtfs/qtfs_server/fsops.c -+++ b/qtfs/qtfs_server/fsops.c -@@ -576,6 +576,7 @@ static int handle_getattr(struct qtserver_arg *arg) - qtfs_debug("handle getattr path:%s\n", req->path); - ret = kern_path(req->path, 0, &path); - if (ret) { -+ rsp->errno = ret; - qtfs_err("handle getattr path:%s failed, ret:%d %s\n", req->path, ret, (ret != -ENOENT) ? "." : "file not exist"); - goto failed; - } -@@ -866,26 +867,27 @@ int handle_xattrlist(struct qtserver_arg *arg) - struct qtrsp_xattrlist *rsp = (struct qtrsp_xattrlist *)RSP(arg); - struct path path; - int ret; -- ssize_t size; -+ ssize_t size, buffer_size; - int i; - -+ buffer_size = req->buffer_size; - ret = kern_path(req->path, 0, &path); - if (ret) { - qtfs_err("handle xattr list path error.\n"); -- rsp->d.errno = -ENOENT; -+ rsp->d.size = -ENOENT; - goto err_handle; - } -- size = generic_listxattr(path.dentry, rsp->name, sizeof(rsp->name)); -+ size = vfs_listxattr(path.dentry, buffer_size == 0 ? NULL : rsp->name, buffer_size); - path_put(&path); - if (size < 0) { - qtfs_err("handle list xattr failed, errno:%ld.\n", size); -- rsp->d.errno = size; -+ rsp->d.size = size; - goto err_handle; - } - if (size == 0) - goto err_handle; - rsp->d.ret = QTFS_OK; -- rsp->d.result = true; -+ rsp->d.size = size; - while (i < size) { - qtfs_info("handle list xattr result:%s\n", &rsp->name[i]); - i += strlen(&rsp->name[i]) + 1; -@@ -894,7 +896,7 @@ int handle_xattrlist(struct qtserver_arg *arg) - - err_handle: - rsp->d.ret = QTFS_ERR; -- rsp->d.result = false; -+ rsp->d.size = size; - return sizeof(struct qtrsp_xattrlist); - } - -@@ -970,9 +972,9 @@ int handle_xattrget(struct qtserver_arg *arg) - } - qtfs_info("handle getxattr: path:%s prefix name:%s : (%s - 0x%llx), size:%ld, reqpos:%d\n", req->path, req->d.prefix_name, kvalue, (__u64)kvalue, error, req->d.pos); - len = (error - req->d.pos)>sizeof(rsp->buf)? sizeof(rsp->buf):(error - req->d.pos); -+ rsp->d.size = len; - if (req->d.size > 0) { - memcpy(rsp->buf, &kvalue[req->d.pos], len); -- rsp->d.size = len; - } - rsp->d.pos = req->d.pos + len; - } else { -diff --git a/qtfs/qtinfo/qtinfo.h b/qtfs/qtinfo/qtinfo.h -index 0244a6e..eb7e8be 100644 ---- a/qtfs/qtinfo/qtinfo.h -+++ b/qtfs/qtinfo/qtinfo.h -@@ -9,29 +9,29 @@ enum qtfs_req_type - QTFS_REQ_OPEN, - QTFS_REQ_CLOSE, - QTFS_REQ_READ, -- QTFS_REQ_READITER, //5 -+ QTFS_REQ_READITER, // 5 - QTFS_REQ_WRITE, - QTFS_REQ_LOOKUP, - QTFS_REQ_READDIR, - QTFS_REQ_MKDIR, -- QTFS_REQ_RMDIR, //10 -+ QTFS_REQ_RMDIR, // 10 - QTFS_REQ_GETATTR, - QTFS_REQ_SETATTR, - QTFS_REQ_ICREATE, - QTFS_REQ_MKNOD, -- QTFS_REQ_UNLINK, //15 -+ QTFS_REQ_UNLINK, // 15 - QTFS_REQ_SYMLINK, - QTFS_REQ_LINK, - QTFS_REQ_GETLINK, - QTFS_REQ_READLINK, -- QTFS_REQ_RENAME, //20 -+ QTFS_REQ_RENAME, // 20 - - QTFS_REQ_XATTRLIST, - QTFS_REQ_XATTRGET, - QTFS_REQ_XATTRSET, - - QTFS_REQ_SYSMOUNT, -- QTFS_REQ_SYSUMOUNT, //25 -+ QTFS_REQ_SYSUMOUNT, // 25 - QTFS_REQ_FIFOPOLL, - - QTFS_REQ_STATFS, -diff --git a/qtfs/req.h b/qtfs/req.h -index 3bcfa77..29f8964 100644 ---- a/qtfs/req.h -+++ b/qtfs/req.h -@@ -414,14 +414,14 @@ struct qtrsp_rename { - // xattr def - #define QTFS_XATTR_LEN 64 - struct qtreq_xattrlist { -+ size_t buffer_size; - char path[MAX_PATH_LEN]; - }; - - struct qtrsp_xattrlist { - struct qtrsp_xattrlist_len { - int ret; -- int errno; -- bool result; -+ ssize_t size; - }d; - char name[QTFS_TAIL_LEN(struct qtrsp_xattrlist_len)]; - }; --- -2.33.0 - diff --git a/0006-add-cmake-compile-for-user-binary-and-so.patch b/0006-add-cmake-compile-for-user-binary-and-so.patch new file mode 100644 index 0000000000000000000000000000000000000000..daa931c5ed30afa8cd8f2bd2373efd9ff30491c4 --- /dev/null +++ b/0006-add-cmake-compile-for-user-binary-and-so.patch @@ -0,0 +1,55 @@ +From fbde8e2d0b6f66daf7aacb7348dffb97721bca7c Mon Sep 17 00:00:00 2001 +From: liqiang +Date: Thu, 8 Jun 2023 15:58:09 +0800 +Subject: add cmake compile for user binary and so + +Signed-off-by: liqiang +--- + qtfs/CMakeLists.txt | 34 ++++++++++++++++++++++++++++++++++ + 1 file changed, 34 insertions(+) + create mode 100644 qtfs/CMakeLists.txt + +diff --git a/qtfs/CMakeLists.txt b/qtfs/CMakeLists.txt +new file mode 100644 +index 0000000..d5b65ec +--- /dev/null ++++ b/qtfs/CMakeLists.txt +@@ -0,0 +1,34 @@ ++cmake_minimum_required(VERSION 3.0.0) ++ ++project(qtfs) ++ ++set(CMAKE_C_FLAGS "-g -O2 -fstack-protector-strong -fPIE -pie -fPIC -D_FORTIFY_SOURCE=2 -s -Wl,-z,now -Wl,-z,noexecstack") ++ ++# Build rexec and rexec_server ++add_executable(rexec rexec/rexec.c rexec/rexec_sock.c) ++add_executable(rexec_server rexec/rexec_server.c rexec/rexec_sock.c rexec/rexec_shim.c) ++target_include_directories(rexec_server PRIVATE /usr/include/glib-2.0 /usr/lib64/glib-2.0/include) ++target_link_libraries(rexec PRIVATE json-c) ++target_link_libraries(rexec_server PRIVATE json-c glib-2.0) ++ ++# Build udsproxyd and libudsproxy.so ++add_executable(udsproxyd ipc/uds_event.c ipc/uds_main.c) ++add_library(udsproxy SHARED ipc/uds_connector.c) ++target_include_directories(udsproxyd PRIVATE include/ /usr/include/glib-2.0 /usr/lib64/glib-2.0/include) ++target_link_libraries(udsproxyd PRIVATE pthread glib-2.0) ++ ++# Build engine ++add_executable(engine ipc/uds_main.c ipc/uds_event.c qtfs_common/user_engine.c) ++target_include_directories(engine PRIVATE include/ ./ ipc/ /usr/include/glib-2.0 /usr/lib64/glib-2.0/include) ++target_link_libraries(engine PRIVATE glib-2.0 pthread) ++target_compile_options(engine PRIVATE "-DQTFS_SERVER") ++ ++if(DEFINED UDS_TEST_MODE OR DEFINED QTFS_TEST_MODE) ++target_compile_options(engine PRIVATE "-DUDS_TEST_MODE") ++target_compile_options(udsproxyd PRIVATE "-DUDS_TEST_MODE") ++message(WARNING "Important risk warning: the test mode is turned on, and qtfs will expose the network port, \ ++ which will bring security risks and is only for testing! If you do not understand the risks,\ ++ please don't use or compile again without test mode macro!") ++endif() ++ ++set(ignoreMe "${QTFS_TEST_MODE}${UDS_TEST_MODE}") +\ No newline at end of file +-- +2.33.0 + diff --git a/0007-Add-whitelist-of-rexec.patch b/0007-Add-whitelist-of-rexec.patch deleted file mode 100644 index 7dfc5c85451e87f8dd3708497c3a20a00df06030..0000000000000000000000000000000000000000 --- a/0007-Add-whitelist-of-rexec.patch +++ /dev/null @@ -1,197 +0,0 @@ -From 92d4368180a81bc4220449f5be6123a1aa32417b Mon Sep 17 00:00:00 2001 -From: yangxin <245051644@qq.com> -Date: Fri, 10 Feb 2023 16:56:58 +0800 -Subject: [PATCH 3/5] Add whitelist of rexec - -Signed-off-by: yangxin <245051644@qq.com> ---- - qtfs/rexec/client.go | 4 +- - qtfs/rexec/common.go | 29 ++++++++++++++ - qtfs/rexec/server.go | 38 ++++++++++++++++++- - .../whitelist/libvirt/rexec_whitelist | 4 ++ - 4 files changed, 72 insertions(+), 3 deletions(-) - create mode 100644 usecases/transparent-offload/whitelist/libvirt/rexec_whitelist - -diff --git a/qtfs/rexec/client.go b/qtfs/rexec/client.go -index 13b63f5..dc1af8b 100644 ---- a/qtfs/rexec/client.go -+++ b/qtfs/rexec/client.go -@@ -156,7 +156,6 @@ func main() { - - retryCnt := 3 - // 1. get pid from response -- time.Sleep(5 * time.Millisecond) - response := &CommandResponse{} - retry: - err = receiver.Receive(response) -@@ -168,6 +167,9 @@ retry: - } - log.Fatal(err) - } -+ if (response.WhiteList == 0) { -+ log.Fatalf("%s command in White List of rexec server\n", command.Cmd) -+ } - pid := response.Pid - lpid := os.Getpid() - log.Printf("create pidFile for %d:%d\n", pid, lpid) -diff --git a/qtfs/rexec/common.go b/qtfs/rexec/common.go -index 9ce21c4..b59b12b 100644 ---- a/qtfs/rexec/common.go -+++ b/qtfs/rexec/common.go -@@ -8,6 +8,7 @@ import ( - "os" - "strconv" - "strings" -+ "syscall" - "io/ioutil" - "encoding/json" - -@@ -30,10 +31,34 @@ type RemoteCommand struct { - Cgroups map[string]string - } - -+func CheckRight(fileName string) error { -+ var uid int -+ var gid int -+ var mode int -+ var stat syscall.Stat_t -+ if err := syscall.Stat(fileName, &stat); err != nil { -+ return fmt.Errorf("Can't get status of %s: %s\n", fileName, err) -+ } -+ uid = int(stat.Uid) -+ gid = int(stat.Gid) -+ mode = int(stat.Mode) -+ -+ if (uid != 0 || gid != 0) { -+ return fmt.Errorf("Owner of %s must be root\n", fileName) -+ } -+ -+ if (mode & 0777 != 0400) { -+ return fmt.Errorf("Mode of %s must be 0400\n", fileName) -+ } -+ -+ return nil -+} -+ - // CommandResponse is the returned response object from the remote execution - type CommandResponse struct { - Pid int - Status int -+ WhiteList int - } - - // NetAddr is struct to describe net proto and addr -@@ -90,6 +115,10 @@ func parseUnixAddr(inAddr string) (NetAddr, error) { - - func readAddrFromFile(role string) (string) { - fileName := fmt.Sprintf("%s/%s.json", configDir, role) -+ if err := CheckRight(fileName); err != nil { -+ fmt.Printf("Check right of %s failed: %s", fileName, err) -+ return "" -+ } - file, err := ioutil.ReadFile(fileName) - if err != nil { - fmt.Printf("read %s failed: %s", fileName, err) -diff --git a/qtfs/rexec/server.go b/qtfs/rexec/server.go -index 4559b79..de3f6cf 100644 ---- a/qtfs/rexec/server.go -+++ b/qtfs/rexec/server.go -@@ -4,6 +4,7 @@ import ( - "crypto/tls" - "fmt" - "io" -+ "io/ioutil" - "log" - "net" - "os" -@@ -17,13 +18,33 @@ import ( - - const ( - role = "server" -+ whiteList = "whitelist" - ) -+var WhiteLists map[string] int -+func getWhitelist() error { -+ fileName := fmt.Sprintf("%s/%s", configDir, whiteList) -+ if err := CheckRight(fileName); err != nil { -+ log.Fatal(err) -+ } -+ file, err := ioutil.ReadFile(fileName) -+ if err != nil { -+ fmt.Printf("read %s failed: %s", fileName, err) -+ return err -+ } -+ fileContent := string(file) -+ lines := strings.Split(fileContent, "\n") -+ for i, v := range lines { -+ WhiteLists[v] = i -+ } -+ return nil -+} - - func getHost(addr string) string { - return strings.Split(addr, ":")[0] - } - - func main() { -+ WhiteLists = make(map[string]int, 10) - cert := os.Getenv("TLS_CERT") - key := os.Getenv("TLS_KEY") - -@@ -32,6 +53,10 @@ func main() { - if err != nil { - log.Fatal(err) - } -+ if err := getWhitelist(); err != nil { -+ log.Println("Get Whitelist failed") -+ return -+ } - if cert != "" && key != "" { - tlsCert, err := tls.LoadX509KeyPair(cert, key) - if err != nil { -@@ -86,13 +111,23 @@ func main() { - } - - command := &RemoteCommand{} -+ returnResult := &CommandResponse{} -+ returnResult.WhiteList = 1 - err = receiver.Receive(command) - if err != nil { - log.Print(err) - return - } - log.Printf("cmd(%s), args(%v)\n", command.Cmd, command.Args) -- -+ if _, ok := WhiteLists[command.Cmd]; !ok { -+ log.Printf("%s not in WhiteLists", command.Cmd) -+ returnResult.WhiteList = 0 -+ err = command.StatusChan.Send(returnResult) -+ if err != nil { -+ log.Print(err) -+ } -+ return -+ } - cmd := exec.Command(command.Cmd, command.Args...) - cmd.Stdout = command.Stdout - cmd.Stderr = command.Stderr -@@ -111,7 +146,6 @@ func main() { - defer command.Stdout.Close() - defer command.Stderr.Close() - -- returnResult := &CommandResponse{} - err = cmd.Start() - if err != nil { - // send return status back -diff --git a/usecases/transparent-offload/whitelist/libvirt/rexec_whitelist b/usecases/transparent-offload/whitelist/libvirt/rexec_whitelist -new file mode 100644 -index 0000000..275a3e5 ---- /dev/null -+++ b/usecases/transparent-offload/whitelist/libvirt/rexec_whitelist -@@ -0,0 +1,4 @@ -+/usr/bin/qemu-kvm -+taskset -+kill -+/usr/bin/kill --- -2.33.0 - diff --git a/0007-uds-remove-MSG_WAITALL-flags-to-timeout.patch b/0007-uds-remove-MSG_WAITALL-flags-to-timeout.patch new file mode 100644 index 0000000000000000000000000000000000000000..46499d3afeb27404aac8dd5409a38d0970573022 --- /dev/null +++ b/0007-uds-remove-MSG_WAITALL-flags-to-timeout.patch @@ -0,0 +1,150 @@ +From 596a9553d90516375de169acdd513e4df26eab9d Mon Sep 17 00:00:00 2001 +From: liqiang +Date: Thu, 8 Jun 2023 15:27:06 +0800 +Subject: uds remove MSG_WAITALL flags to timeout + +Signed-off-by: liqiang +--- + qtfs/ipc/uds_event.c | 16 ++++++++-------- + qtfs/ipc/uds_main.c | 36 ++++++++++++++++++++++++++++++++++++ + qtfs/ipc/uds_main.h | 1 + + 3 files changed, 45 insertions(+), 8 deletions(-) + +diff --git a/qtfs/ipc/uds_event.c b/qtfs/ipc/uds_event.c +index b046b69..047949b 100644 +--- a/qtfs/ipc/uds_event.c ++++ b/qtfs/ipc/uds_event.c +@@ -214,7 +214,7 @@ int uds_event_build_step2(void *arg, int epfd, struct uds_event_global_var *p_ev + struct uds_proxy_remote_conn_rsp rsp; + int len; + memset(buf, 0, sizeof(buf)); +- len = recv(evt->fd, msg, sizeof(struct uds_proxy_remote_conn_req), MSG_WAITALL); ++ len = uds_recv_with_timeout(evt->fd, msg, sizeof(struct uds_proxy_remote_conn_req)); + if (len == 0) { + uds_err("recv err msg:%d errno:%d", len, errno); + return EVENT_DEL; +@@ -390,7 +390,7 @@ int uds_event_tcp_listener(void *arg, int epfd, struct uds_event_global_var *p_e + int uds_build_connect2uds(struct uds_event *evt, struct uds_proxy_remote_conn_req *msg) + { + struct uds_conn_arg targ; +- int len = recv(evt->fd, msg, sizeof(struct uds_proxy_remote_conn_req), MSG_WAITALL); ++ int len = uds_recv_with_timeout(evt->fd, msg, sizeof(struct uds_proxy_remote_conn_req)); + if (len <= 0) { + uds_err("recv failed, len:%d errno:%d", len, errno); + return EVENT_ERR; +@@ -441,7 +441,7 @@ err_ack: + + int uds_build_pipe_proxy(int efd, struct uds_event *evt, struct uds_stru_scm_pipe *msg) + { +- int len = recv(evt->fd, msg, sizeof(struct uds_stru_scm_pipe), MSG_WAITALL); ++ int len = uds_recv_with_timeout(evt->fd, msg, sizeof(struct uds_stru_scm_pipe)); + if (len <= 0) { + uds_err("recv failed, len:%d errno:%d", len, errno); + return EVENT_ERR; +@@ -477,7 +477,7 @@ int uds_event_remote_build(void *arg, int epfd, struct uds_event_global_var *p_e + int len; + int ret = EVENT_OK; + memset(p_event_var->iov_base, 0, p_event_var->iov_len); +- len = recv(evt->fd, bdmsg, sizeof(struct uds_tcp2tcp), MSG_WAITALL); ++ len = uds_recv_with_timeout(evt->fd, bdmsg, sizeof(struct uds_tcp2tcp)); + if (len <= 0) { + uds_err("read no msg from sock:%d, len:%d", evt->fd, len); + return EVENT_DEL; +@@ -711,7 +711,7 @@ int uds_msg_tcp2uds_scm_pipe(struct uds_tcp2tcp *p_msg, struct uds_event *evt, i + int scmfd; + int fd[SCM_PIPE_NUM]; + struct uds_stru_scm_pipe *p_pipe = (struct uds_stru_scm_pipe *)p_msg->data; +- int len = recv(evt->fd, p_pipe, p_msg->msglen, MSG_WAITALL); ++ int len = uds_recv_with_timeout(evt->fd, p_pipe, p_msg->msglen); + if (len <= 0) { + uds_err("recv data failed, len:%d", len); + return EVENT_DEL; +@@ -913,7 +913,7 @@ int uds_event_tcp2uds(void *arg, int epfd, struct uds_event_global_var *p_event_ + msg.msg_controllen = p_event_var->msg_controlsendlen; + + while (1) { +- int len = recv(evt->fd, p_msg, sizeof(struct uds_tcp2tcp), MSG_WAITALL); ++ int len = uds_recv_with_timeout(evt->fd, p_msg, sizeof(struct uds_tcp2tcp)); + if (len <= 0) { + uds_err("recv no msg maybe sock is closed, delete this tcp2uds event, len:%d.", len); + goto close_event; +@@ -932,7 +932,7 @@ int uds_event_tcp2uds(void *arg, int epfd, struct uds_event_global_var *p_event_ + uds_err("normal msg repeat recv fd:%d", evt->fd); + goto err; + } +- normal_msg_len = recv(evt->fd, p_event_var->iov_base_send, p_msg->msglen, MSG_WAITALL); ++ normal_msg_len = uds_recv_with_timeout(evt->fd, p_event_var->iov_base_send, p_msg->msglen); + if (normal_msg_len <= 0) { + uds_err("recv msg error:%d fd:%d", len, evt->fd); + goto close_event; +@@ -950,7 +950,7 @@ int uds_event_tcp2uds(void *arg, int epfd, struct uds_event_global_var *p_event_ + } + memset(p_scm->path, 0, sizeof(p_scm->path)); + // SCM RIGHTS msg proc +- len = recv(evt->fd, p_msg->data, p_msg->msglen, MSG_WAITALL); ++ len = uds_recv_with_timeout(evt->fd, p_msg->data, p_msg->msglen); + if (len <= 0) { + uds_err("recv data failed len:%d", p_msg->msglen); + return EVENT_DEL; +diff --git a/qtfs/ipc/uds_main.c b/qtfs/ipc/uds_main.c +index adf0936..65ae81d 100644 +--- a/qtfs/ipc/uds_main.c ++++ b/qtfs/ipc/uds_main.c +@@ -88,6 +88,42 @@ int uds_event_delete(int efd, int fd) + return 0; + } + ++int uds_recv_with_timeout(int fd, char *msg, int len) ++{ ++#define TMOUT_BLOCK_SIZE 1024 ++#define TMOUT_UNIT_MS 20 ++#define TMOUT_INTERVAL 1 ++#define TMOUT_MAX_MS 1000 ++ int total_recv = 0; ++ int ret; ++ int tmout_ms = ((len / TMOUT_BLOCK_SIZE) + 1) * TMOUT_UNIT_MS; ++ if (len <= 0 || msg == NULL || fd < 0) { ++ uds_err("invalid param fd:%d len:%d or %s", fd, len, (msg == NULL) ? "msg is NULL" : "msg is not NULL"); ++ return 0; ++ } ++ if (tmout_ms > TMOUT_MAX_MS) ++ tmout_ms = TMOUT_MAX_MS; ++ do { ++ ret = recv(fd, &msg[total_recv], len - total_recv, 0); ++ if (ret < 0) { ++ uds_err("recv failed ret:%d errno:%d", ret, errno); ++ return ret; ++ } ++ total_recv += ret; ++ if (total_recv > len) { ++ uds_err("fatal error total recv:%d longger than target len:%d", total_recv, len); ++ return 0; ++ } ++ if (total_recv == len) { ++ return total_recv; ++ } ++ usleep(TMOUT_INTERVAL * 1000); ++ tmout_ms -= TMOUT_INTERVAL; ++ } while (tmout_ms > 0); ++ uds_err("Fatal error, the target recv len:%d and only %d length is received when it time out", len, total_recv); ++ return 0; ++} ++ + #pragma GCC diagnostic ignored "-Wpointer-to-int-cast" + int uds_event_tmout_item(gpointer key, gpointer value, gpointer data) + { +diff --git a/qtfs/ipc/uds_main.h b/qtfs/ipc/uds_main.h +index de400f8..f69e4b3 100644 +--- a/qtfs/ipc/uds_main.h ++++ b/qtfs/ipc/uds_main.h +@@ -152,6 +152,7 @@ int uds_event_insert(int efd, struct uds_event *event); + int uds_hash_insert_dirct(GHashTable *table, int key, struct uds_event *value); + void *uds_hash_lookup_dirct(GHashTable *table, int key); + int uds_hash_remove_dirct(GHashTable *table, int key); ++int uds_recv_with_timeout(int fd, char *msg, int len); + + #ifdef QTFS_SERVER + int uds_proxy_main(int argc, char *argv[]); +-- +2.33.0 + diff --git a/0008-Add-udsproxy.patch b/0008-Add-udsproxy.patch deleted file mode 100644 index 6ccc3b0f1178c6cfff0bf3298034f83b13e8e464..0000000000000000000000000000000000000000 --- a/0008-Add-udsproxy.patch +++ /dev/null @@ -1,2812 +0,0 @@ -From 435916d197bfce059e3afbca0975315fc5b1662f Mon Sep 17 00:00:00 2001 -From: yangxin <245051644@qq.com> -Date: Fri, 10 Feb 2023 17:02:05 +0800 -Subject: [PATCH 4/5] Add udsproxy. - -Signed-off-by: yangxin <245051644@qq.com> ---- - qtfs/README.md | 7 +- - qtfs/comm.h | 8 +- - qtfs/conn.c | 9 +- - qtfs/conn.h | 1 + - qtfs/ipc/Makefile | 22 + - qtfs/ipc/uds_connector.c | 129 +++++ - qtfs/ipc/uds_event.c | 999 +++++++++++++++++++++++++++++++++ - qtfs/ipc/uds_event.h | 64 +++ - qtfs/ipc/uds_main.c | 556 ++++++++++++++++++ - qtfs/ipc/uds_main.h | 141 +++++ - qtfs/ipc/uds_module.h | 19 + - qtfs/misc.c | 7 + - qtfs/qtfs/sb.c | 6 +- - qtfs/qtfs_server/Makefile | 17 +- - qtfs/qtfs_server/fsops.c | 5 +- - qtfs/qtfs_server/qtfs-server.c | 11 +- - qtfs/qtfs_server/user_engine.c | 26 +- - qtfs/qtinfo/qtinfo.c | 77 ++- - qtfs/qtsock.c | 332 +++++++++++ - 19 files changed, 2406 insertions(+), 30 deletions(-) - create mode 100644 qtfs/ipc/Makefile - create mode 100644 qtfs/ipc/uds_connector.c - create mode 100644 qtfs/ipc/uds_event.c - create mode 100644 qtfs/ipc/uds_event.h - create mode 100644 qtfs/ipc/uds_main.c - create mode 100644 qtfs/ipc/uds_main.h - create mode 100644 qtfs/ipc/uds_module.h - create mode 100644 qtfs/qtsock.c - -diff --git a/qtfs/README.md b/qtfs/README.md -index 0cbc2e1..19987e0 100644 ---- a/qtfs/README.md -+++ b/qtfs/README.md -@@ -24,6 +24,7 @@ qtfs的特性: - ## 安装教程 - - 目录说明: -++ **ipc**: 跨主机unix domain socket协同组件,在该目录下编译udsproxyd二进制和libudsproxy.so库。 - + **qtfs**: 客户端内核模块相关代码,直接在该目录下编译客户端ko。 - + **qtfs_server**: 服务端内核模块相关代码,直接在该目录下编译服务端ko和相关程序。 - + **qtinfo**: 诊断工具,支持查询文件系统的工作状态以及修改log级别等。 -@@ -34,19 +35,23 @@ qtfs的特性: - - 1. 要求内核版本在5.10或更高版本。 - 2. 安装内核开发包:yum install kernel-devel。 -+ 3. 假设host服务器ip为192.168.10.10,dpu为192.168.10.11 - - 服务端安装: - - 1. cd qtfs_server - 2. make clean && make - 3. insmod qtfs_server.ko qtfs_server_ip=x.x.x.x qtfs_server_port=12345 qtfs_log_level=WARN -- 4. ./engine 4096 16 -+ 4. nohup ./engine 16 1 192.168.10.10 12121 192.168.10.11 12121 2>&1 & - - 客户端安装: - - 1. cd qtfs - 2. make clean && make - 3. insmod qtfs.ko qtfs_server_ip=x.x.x.x qtfs_server_port=12345 qtfs_log_level=WARN -+ 4. cd ../ipc/ -+ 5. make clean && make && make install -+ 6. nohup udsproxyd 1 192.168.10.11 12121 192.168.10.10 12121 2>&1 & - - ## 使用说明 - -diff --git a/qtfs/comm.h b/qtfs/comm.h -index 901552c..2e562bb 100644 ---- a/qtfs/comm.h -+++ b/qtfs/comm.h -@@ -3,6 +3,9 @@ - - extern struct qtinfo *qtfs_diag_info; - -+#define QTFS_CLIENT_DEV "/dev/qtfs_client" -+#define QTFS_SERVER_DEV "/dev/qtfs_server" -+ - #define QTFS_IOCTL_MAGIC 'Q' - enum { - _QTFS_IOCTL_EXEC, -@@ -18,6 +21,7 @@ enum { - - _QTFS_IOCTL_LOG_LEVEL, - _QTFS_IOCTL_EPOLL_SUPPORT, -+ _QTFS_IOCTL_UDS_PROXY_PID, - }; - - #define QTFS_IOCTL_THREAD_INIT _IO(QTFS_IOCTL_MAGIC, _QTFS_IOCTL_EXEC) -@@ -31,6 +35,7 @@ enum { - #define QTFS_IOCTL_CLEARALL _IO(QTFS_IOCTL_MAGIC, _QTFS_IOCTL_CLEARALL) - #define QTFS_IOCTL_LOGLEVEL _IO(QTFS_IOCTL_MAGIC, _QTFS_IOCTL_LOG_LEVEL) - #define QTFS_IOCTL_EPOLL_SUPPORT _IO(QTFS_IOCTL_MAGIC, _QTFS_IOCTL_EPOLL_SUPPORT) -+#define QTFS_IOCTL_UDS_PROXY_PID _IO(QTFS_IOCTL_MAGIC, _QTFS_IOCTL_UDS_PROXY_PID) - - #define QTINFO_MAX_EVENT_TYPE 36 // look qtreq_type at req.h - #define QTFS_FUNCTION_LEN 64 -@@ -119,6 +124,7 @@ enum qtinfo_cnts { - }; - #endif - -+#if (defined(QTFS_CLIENT) || defined(client) || defined(QTFS_SERVER) || defined(server)) - // for connection state machine - typedef enum { - QTCONN_INIT, -@@ -159,7 +165,7 @@ struct qtinfo { - #define QTINFO_STATE(state) ((state == QTCONN_INIT) ? "INIT" : \ - ((state == QTCONN_CONNECTING) ? "CONNECTING" : \ - ((state == QTCONN_ACTIVE) ? "ACTIVE" : "UNKNOWN"))) -- -+#endif - //ko compile - #if (defined(QTFS_CLIENT) || defined(client)) - static inline void qtinfo_clear(void) -diff --git a/qtfs/conn.c b/qtfs/conn.c -index 26930b1..c84c85c 100644 ---- a/qtfs/conn.c -+++ b/qtfs/conn.c -@@ -32,6 +32,7 @@ struct qtfs_sock_var_s *qtfs_epoll_var = NULL; - struct socket *qtfs_server_main_sock = NULL; - struct qtfs_server_userp_s *qtfs_userps = NULL; - #endif -+int qtfs_uds_proxy_pid = -1; - #define QTFS_EPOLL_THREADIDX (QTFS_MAX_THREADS + 4) - - -@@ -76,6 +77,10 @@ static int qtfs_conn_sockserver_init(struct qtfs_sock_var_s *pvar) - { - struct socket *sock; - int ret; -+ struct sockaddr_in saddr; -+ saddr.sin_family = AF_INET; -+ saddr.sin_port = htons(pvar->port); -+ saddr.sin_addr.s_addr = in_aton(pvar->addr); - - if (!QTCONN_IS_EPOLL_CONN(pvar) && qtfs_server_main_sock != NULL) { - qtfs_info("qtfs server main sock is %lx, valid or out-of-date?", (unsigned long)qtfs_server_main_sock); -@@ -147,10 +152,6 @@ static int qtfs_conn_sockclient_init(struct qtfs_sock_var_s *pvar) - { - struct socket *sock; - int ret; -- struct sockaddr_in saddr; -- saddr.sin_family = AF_INET; -- saddr.sin_port = htons(pvar->port); -- saddr.sin_addr.s_addr = in_aton(pvar->addr); - - ret = sock_create_kern(&init_net, AF_INET, SOCK_STREAM, 0, &sock); - if (ret) { -diff --git a/qtfs/conn.h b/qtfs/conn.h -index db590fc..742def4 100644 ---- a/qtfs/conn.h -+++ b/qtfs/conn.h -@@ -26,6 +26,7 @@ extern char qtfs_log_level[QTFS_LOGLEVEL_STRLEN]; - extern int log_level; - extern struct qtinfo *qtfs_diag_info; - extern bool qtfs_epoll_mode; -+extern int qtfs_uds_proxy_pid; - - #define qtfs_conn_get_param(void) _qtfs_conn_get_param(__func__) - -diff --git a/qtfs/ipc/Makefile b/qtfs/ipc/Makefile -new file mode 100644 -index 0000000..47e74ad ---- /dev/null -+++ b/qtfs/ipc/Makefile -@@ -0,0 +1,22 @@ -+all: udsproxyd libudsproxy.so -+ -+udsproxyd: uds_event.o uds_main.o -+ gcc -g -O2 -o udsproxyd $^ -I../ -+ -+uds_event.o: -+ cc -g -c -o uds_event.o uds_event.c -+ -+uds_main.o: -+ cc -g -c -o uds_main.o uds_main.c -+ -+libudsproxy.so: -+ gcc -g -O2 -o libudsproxy.so uds_connector.c -fPIC --shared -+ -+install: -+ yes | cp udsproxyd /usr/bin/ -+ yes | cp libudsproxy.so /usr/lib64/ -+ -+clean: -+ @rm -rf *.o udsproxyd libudsproxy.so -+ -+.PHONY: clean -diff --git a/qtfs/ipc/uds_connector.c b/qtfs/ipc/uds_connector.c -new file mode 100644 -index 0000000..3c46ce5 ---- /dev/null -+++ b/qtfs/ipc/uds_connector.c -@@ -0,0 +1,129 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "uds_module.h" -+ -+#define uds_log(info, ...) \ -+ do { \ -+ time_t t; \ -+ struct tm *p; \ -+ time(&t); \ -+ p = localtime(&t); \ -+ printf("[%d/%02d/%02d %02d:%02d:%02d][LOG:%s:%3d]"info"\n", \ -+ p->tm_year + 1900, p->tm_mon+1, p->tm_mday, \ -+ p->tm_hour, p->tm_min, p->tm_sec, __func__, __LINE__, ##__VA_ARGS__); \ -+ } while (0); -+ -+#define uds_err(info, ...) \ -+ do { \ -+ time_t t; \ -+ struct tm *p; \ -+ time(&t); \ -+ p = localtime(&t); \ -+ printf("[%d/%02d/%02d %02d:%02d:%02d][LOG:%s:%3d]"info"\n", \ -+ p->tm_year + 1900, p->tm_mon+1, p->tm_mday, \ -+ p->tm_hour, p->tm_min, p->tm_sec, __func__, __LINE__, ##__VA_ARGS__); \ -+ } while (0); -+ -+static unsigned short uds_conn_get_sock_type(int sockfd) -+{ -+ unsigned short type; -+ int len = 2; -+ int ret = getsockopt(sockfd, SOL_SOCKET, SO_TYPE, &type, &len); -+ if (ret < 0) { -+ uds_err("get sock type failed, fd:%d", sockfd); -+ return (unsigned short)-1; -+ } -+ uds_log("fd:%d type:%d", sockfd, type); -+ return type; -+} -+ -+static int uds_conn_whitelist_check(const char *path) -+{ -+ return 1; -+} -+ -+int connect(int fd, const struct sockaddr *addrarg, socklen_t len) -+{ -+ int sock_fd; -+ typeof(connect) *libcconnect = NULL; -+ int libcret; -+ const struct sockaddr_un *addr = (const struct sockaddr_un *)addrarg; -+ -+ if (libcconnect == NULL) { -+ libcconnect = dlsym(((void *) - 1l), "connect"); -+ if (libcconnect == NULL) { -+ uds_err("can't find connect by dlsym."); -+ return -1; -+ } -+ } -+ -+ libcret = (*libcconnect)(fd, addrarg, len); -+ if (libcret == 0 || addr->sun_family != AF_UNIX) { -+ // 如果本地connect成功,或者非UNIX DOMAIN SOCKET,都直接返回即可 -+ return libcret; -+ } -+ -+ uds_log("enter uds connect fd:%d sunpath:%s family:%d len:%d connect function:0x%lx", fd, addr->sun_path, -+ addr->sun_family, len, libcconnect); -+ // 本地未连接,且是uds链接 -+ if (!uds_conn_whitelist_check(addr->sun_path)) { -+ uds_err("path:%s not in white list", addr->sun_path); -+ return libcret; -+ } -+ -+ // 尝试远端链接 -+ do { -+ int ret; -+ struct uds_proxy_remote_conn_req remoteconn; -+ struct uds_proxy_remote_conn_rsp remotersp; -+ struct sockaddr_un proxy = {.sun_family = AF_UNIX}; -+ sock_fd = socket(AF_UNIX, SOCK_STREAM, 0); -+ if (sock_fd < 0) { -+ uds_err("create socket failed"); -+ return libcret; -+ } -+ -+ strncpy(proxy.sun_path, UDS_BUILD_CONN_ADDR, sizeof(proxy.sun_path)); -+ if ((*libcconnect)(sock_fd, (struct sockaddr *)&proxy, sizeof(struct sockaddr_un)) < 0) { -+ uds_err("can't connect to uds proxy: %s", UDS_BUILD_CONN_ADDR); -+ goto err_end; -+ } -+ // 这里type需要是第一个入参fd的type -+ remoteconn.type = uds_conn_get_sock_type(fd); -+ if (remoteconn.type == (unsigned short)-1) { -+ remoteconn.type = SOCK_STREAM; -+ } -+ memset(remoteconn.sun_path, 0, sizeof(remoteconn.sun_path)); -+ strncpy(remoteconn.sun_path, addr->sun_path, sizeof(remoteconn.sun_path)); -+ ret = send(sock_fd, &remoteconn, sizeof(remoteconn), 0); -+ if (ret <= 0) { -+ uds_err("send remote connect request failed, ret:%d err:%s", ret, strerror(errno)); -+ goto err_end; -+ } -+ ret = recv(sock_fd, &remotersp, sizeof(remotersp), MSG_WAITALL); -+ if (ret <= 0) { -+ uds_err("recv remote connect replay failed, ret:%d err:%s", ret, strerror(errno)); -+ goto err_end; -+ } -+ if (remotersp.ret == 0) { -+ goto err_end; -+ } -+ } while(0); -+ -+ close(sock_fd); -+ return (*libcconnect)(fd, addrarg, len); -+ -+err_end: -+ close(sock_fd); -+ return libcret; -+} -diff --git a/qtfs/ipc/uds_event.c b/qtfs/ipc/uds_event.c -new file mode 100644 -index 0000000..ff4d79b ---- /dev/null -+++ b/qtfs/ipc/uds_event.c -@@ -0,0 +1,999 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "dirent.h" -+ -+#include "uds_main.h" -+#include "uds_event.h" -+ -+int uds_event_build_step2(void *arg, int epfd, struct uds_event_global_var *p_event_var); -+int uds_event_remote_build(void *arg, int epfd, struct uds_event_global_var *p_event_var); -+int uds_event_build_step3(void *arg, int epfd, struct uds_event_global_var *p_event_var); -+int uds_event_uds2tcp(void *arg, int epfd, struct uds_event_global_var *p_event_var); -+int uds_event_tcp2uds(void *arg, int epfd, struct uds_event_global_var *p_event_var); -+int uds_event_build_step4(void *arg, int epfd, struct uds_event_global_var *p_event_var); -+int uds_event_tcp2pipe(void *arg, int epfd, struct uds_event_global_var *p_event_var); -+int uds_event_pipe2tcp(void *arg, int epfd, struct uds_event_global_var *p_event_var); -+ -+int uds_event_module_init(struct uds_event_global_var *p) -+{ -+ p->msg_controllen = UDS_EVENT_BUFLEN; -+ p->iov_len = UDS_EVENT_BUFLEN; -+ p->buflen = UDS_EVENT_BUFLEN; -+ p->msg_controlsendlen = UDS_EVENT_BUFLEN; -+ p->iov_sendlen = UDS_EVENT_BUFLEN; -+ -+ p->msg_control = (char *)malloc(p->msg_controllen); -+ if (p->msg_control == NULL) { -+ uds_err("malloc msg control buf failed."); -+ p->msg_controllen = 0; -+ return EVENT_ERR; -+ } -+ p->msg_control_send = (char *)malloc(p->msg_controlsendlen); -+ if (p->msg_control_send == NULL) { -+ goto free1; -+ } -+ p->iov_base = (char *)malloc(p->iov_len); -+ if (p->iov_base == NULL) { -+ uds_err("malloc iov base failed."); -+ goto free2; -+ } -+ p->iov_base_send = (char *)malloc(p->iov_sendlen); -+ if (p->iov_base_send == NULL) { -+ goto free3; -+ } -+ p->buf = (char *)malloc(p->buflen); -+ if (p->buf == NULL) { -+ uds_err("malloc buf failed."); -+ goto free4; -+ } -+ return EVENT_OK; -+ -+free4: -+ free(p->iov_base_send); -+ p->iov_base_send = NULL; -+ -+free3: -+ free(p->iov_base); -+ p->iov_base = NULL; -+ -+free2: -+ free(p->msg_control_send); -+ p->msg_control_send = NULL; -+ -+free1: -+ free(p->msg_control); -+ p->msg_control = NULL; -+ return EVENT_ERR; -+} -+ -+void uds_event_module_fini(struct uds_event_global_var *p) -+{ -+ if (p->msg_control != NULL) { -+ free(p->msg_control); -+ p->msg_control = NULL; -+ p->msg_controllen = 0; -+ } -+ if (p->msg_control_send != NULL) { -+ free(p->msg_control_send); -+ p->msg_control_send = NULL; -+ p->msg_controlsendlen = 0; -+ } -+ if (p->iov_base != NULL) { -+ free(p->iov_base); -+ p->iov_base = NULL; -+ p->iov_len = 0; -+ } -+ if (p->iov_base_send != NULL) { -+ free(p->iov_base_send); -+ p->iov_base_send = NULL; -+ p->iov_sendlen = 0; -+ } -+ if (p->buf != NULL) { -+ free(p->buf); -+ p->buf = NULL; -+ p->buflen = 0; -+ } -+ return; -+} -+ -+int uds_event_pre_hook(struct uds_event_global_var *p_event_var) -+{ -+ p_event_var->cur = 0; -+ memset(p_event_var->tofree, 0, sizeof(struct uds_event *) * UDS_EPOLL_MAX_EVENTS); -+ return 0; -+} -+ -+int uds_event_post_hook(struct uds_event_global_var *p_event_var) -+{ -+ for (int i = 0; i < p_event_var->cur; i++) { -+ uds_log("event:%lx fd:%d free by its peer", p_event_var->tofree[i], p_event_var->tofree[i]->fd); -+ uds_del_event(p_event_var->tofree[i]); -+ } -+ return 0; -+} -+ -+int uds_event_add_to_free(struct uds_event_global_var *p_event_var, struct uds_event *evt) -+{ -+ if (evt->pipe == 1) { -+ uds_log("pipe event:%d no need to free peer", evt->fd); -+ return 0; -+ } -+ -+ struct uds_event *peerevt = evt->peer; -+ if (peerevt == NULL) { -+ uds_err("peer event add to free is NULL, my fd:%d", evt->fd); -+ return -1; -+ } -+ peerevt->tofree = 1; -+ uds_log("event fd:%d addr:%lx add to free", peerevt->fd, peerevt); -+ p_event_var->tofree[p_event_var->cur] = peerevt; -+ p_event_var->cur++; -+ return 0; -+} -+ -+int uds_event_pre_handler(struct uds_event *evt) -+{ -+ if (evt->tofree == 1) { -+ uds_log("event fd:%d marked by peer as pending deletion", evt->fd); -+ return EVENT_ERR; -+ } -+ return EVENT_OK; -+} -+ -+/* -+ * 1. accept local uds connect request -+ * 2. set new connection's event to build link step2 -+ * 3. add new connection event to epoll list -+ */ -+int uds_event_uds_listener(void *arg, int epfd, struct uds_event_global_var *p_event_var) -+{ -+ int connfd; -+ struct uds_event *evt = (struct uds_event *)arg; -+ if (evt == NULL) { -+ uds_err("param is invalid."); -+ return EVENT_ERR; -+ } -+ connfd = uds_sock_step_accept(evt->fd, AF_UNIX); -+ if (connfd <= 0) { -+ uds_err("conn fd error:%d", connfd); -+ return EVENT_ERR; -+ } -+ -+ uds_log("accept an new connection, fd:%d", connfd); -+ -+ uds_add_event(connfd, NULL, uds_event_build_step2, NULL); -+ return EVENT_OK; -+} -+ -+int uds_event_build_step2(void *arg, int epfd, struct uds_event_global_var *p_event_var) -+{ -+ struct uds_event *evt = (struct uds_event *)arg; -+ if (evt == NULL) { -+ uds_err("param is invalid."); -+ return EVENT_ERR; -+ } -+ char buf[sizeof(struct uds_tcp2tcp) + sizeof(struct uds_proxy_remote_conn_req)] = {0}; -+ struct uds_tcp2tcp *bdmsg = (struct uds_tcp2tcp *)buf; -+ struct uds_proxy_remote_conn_req *msg = (struct uds_proxy_remote_conn_req *)bdmsg->data; -+ int len; -+ memset(buf, 0, sizeof(buf)); -+ len = recv(evt->fd, msg, sizeof(struct uds_proxy_remote_conn_req), MSG_WAITALL); -+ if (len == 0) { -+ uds_err("recv err msg:%d errno:%s", len, strerror(errno)); -+ return EVENT_DEL; -+ } -+ if (len < 0) { -+ uds_err("read msg error:%d errno:%s", len, strerror(errno)); -+ goto end; -+ } -+ if (msg->type != SOCK_STREAM && msg->type != SOCK_DGRAM) { -+ uds_err("uds type:%d invalid", msg->type); -+ return EVENT_ERR; -+ } -+ -+ struct uds_conn_arg tcp = { -+ .cs = UDS_SOCKET_CLIENT, -+ }; -+ int ret; -+ if ((ret = uds_build_tcp_connection(&tcp)) < 0) { -+ uds_err("step2 build tcp connection failed, return:%d", ret); -+ goto end; -+ } -+ bdmsg->msgtype = MSGCNTL_UDS; -+ bdmsg->msglen = sizeof(struct uds_proxy_remote_conn_req); -+ if (write(tcp.connfd, bdmsg, sizeof(struct uds_tcp2tcp) + sizeof(struct uds_proxy_remote_conn_req)) < 0) { -+ uds_err("send msg to tcp failed"); -+ goto end; -+ } -+ -+ struct uds_proxy_remote_conn_req *priv = (void *)malloc(sizeof(struct uds_proxy_remote_conn_req)); -+ if (priv == NULL) { -+ uds_err("malloc failed"); -+ goto end; -+ } -+ -+ uds_log("step2 recv sun path:%s, add step3 event fd:%d", msg->sun_path, tcp.connfd); -+ memcpy(priv, msg, sizeof(struct uds_proxy_remote_conn_req)); -+ uds_add_event(tcp.connfd, evt, uds_event_build_step3, priv); -+ -+end: -+ return EVENT_OK; -+} -+ -+ -+int uds_event_build_step3(void *arg, int epfd, struct uds_event_global_var *p_event_var) -+{ -+ struct uds_event *evt = (struct uds_event *)arg; -+ struct uds_proxy_remote_conn_rsp msg; -+ int len; -+ memset(&msg, 0, sizeof(struct uds_proxy_remote_conn_rsp)); -+ len = read(evt->fd, &msg, sizeof(struct uds_proxy_remote_conn_rsp)); -+ if (len <= 0) { -+ uds_err("read error len:%d", len); -+ if (len == 0) -+ goto event_del; -+ return EVENT_ERR; -+ } -+ if (msg.ret == EVENT_ERR) { -+ uds_log("get build ack:%d, failed", msg.ret); -+ goto event_del; -+ } -+ -+ struct uds_proxy_remote_conn_req *udsmsg = (struct uds_proxy_remote_conn_req *)evt->priv; -+ struct uds_conn_arg uds; -+ -+ memset(&uds, 0, sizeof(struct uds_conn_arg)); -+ uds.cs = UDS_SOCKET_SERVER; -+ uds.udstype = udsmsg->type; -+ strncpy(uds.sun_path, udsmsg->sun_path, sizeof(uds.sun_path)); -+ if (uds_build_unix_connection(&uds) < 0) { -+ uds_err("failed to build uds server sunpath:%s", uds.sun_path); -+ goto event_del; -+ } -+ uds_log("remote conn build success, build uds server type:%d sunpath:%s fd:%d OK this event suspend,", -+ udsmsg->type, udsmsg->sun_path, uds.sockfd); -+ uds_event_suspend(epfd, evt); -+ uds_add_event(uds.sockfd, evt, uds_event_build_step4, NULL); -+ -+ msg.ret = 1; -+ write(evt->peer->fd, &msg, sizeof(struct uds_proxy_remote_conn_rsp)); -+ return EVENT_OK; -+ -+event_del: -+ msg.ret = 0; -+ write(evt->peer->fd, &msg, sizeof(struct uds_proxy_remote_conn_rsp)); -+ free(evt->priv); -+ return EVENT_DEL; -+} -+ -+int uds_event_build_step4(void *arg, int epfd, struct uds_event_global_var *p_event_var) -+{ -+ struct uds_event *evt = (struct uds_event *)arg; -+ int connfd = uds_sock_step_accept(evt->fd, AF_UNIX); -+ if (connfd < 0) { -+ uds_err("accept connection failed fd:%d", connfd); -+ return EVENT_ERR; -+ } -+ struct uds_event *peerevt = (struct uds_event *)evt->peer; -+ peerevt->handler = uds_event_tcp2uds; -+ peerevt->peer = uds_add_event(connfd, peerevt, uds_event_uds2tcp, NULL); -+ -+ uds_log("accept new connection fd:%d, peerfd:%d frontfd:%d peerfd:%d, peerevt(fd:%d) active now", -+ connfd, evt->peer->fd, peerevt->fd, peerevt->peer->fd, peerevt->fd); -+ uds_event_insert(epfd, peerevt); -+ return EVENT_DEL; -+} -+ -+int uds_event_tcp_listener(void *arg, int epfd, struct uds_event_global_var *p_event_var) -+{ -+ struct uds_event *evt = (struct uds_event *)arg; -+ int connfd = uds_sock_step_accept(evt->fd, AF_INET); -+ if (connfd <= 0) { -+ uds_err("tcp conn fd error:%d", connfd); -+ return EVENT_ERR; -+ } -+ uds_log("tcp listener event enter, new connection fd:%d.", connfd); -+ -+ uds_add_event(connfd, NULL, uds_event_remote_build, NULL); -+ return 0; -+} -+ -+int uds_build_connect2uds(struct uds_event *evt, struct uds_proxy_remote_conn_req *msg) -+{ -+ struct uds_conn_arg targ; -+ int len = recv(evt->fd, msg, sizeof(struct uds_proxy_remote_conn_req), MSG_WAITALL); -+ if (len <= 0) { -+ uds_err("recv failed, len:%d str:%s", len, strerror(errno)); -+ return EVENT_ERR; -+ } -+ -+ targ.cs = UDS_SOCKET_CLIENT; -+ targ.udstype = msg->type; -+ memset(targ.sun_path, 0, sizeof(targ.sun_path)); -+ strncpy(targ.sun_path, msg->sun_path, sizeof(targ.sun_path)); -+ if (uds_build_unix_connection(&targ) < 0) { -+ struct uds_proxy_remote_conn_rsp ack; -+ uds_err("can't connect to sun_path:%s", targ.sun_path); -+ ack.ret = EVENT_ERR; -+ write(evt->fd, &ack, sizeof(struct uds_proxy_remote_conn_rsp)); -+ return EVENT_DEL; -+ } -+ -+ evt->peer = uds_add_event(targ.connfd, evt, uds_event_uds2tcp, NULL); -+ evt->handler = uds_event_tcp2uds; -+ -+ uds_log("build link req from tcp, sunpath:%s, type:%d, eventfd:%d peerfd:%d", -+ msg->sun_path, msg->type, targ.connfd, evt->fd); -+ -+ struct uds_proxy_remote_conn_rsp ack; -+ ack.ret = EVENT_OK; -+ -+ int ret = write(evt->fd, &ack, sizeof(struct uds_proxy_remote_conn_rsp)); -+ if (ret <= 0) { -+ uds_err("apply ack failed, ret:%d", ret); -+ return EVENT_DEL; -+ } -+ return EVENT_OK; -+} -+ -+int uds_build_pipe_proxy(struct uds_event *evt, struct uds_stru_scm_pipe *msg) -+{ -+ int len = recv(evt->fd, msg, sizeof(struct uds_stru_scm_pipe), MSG_WAITALL); -+ if (len <= 0) { -+ uds_err("recv failed, len:%d str:%s", len, strerror(errno)); -+ return EVENT_ERR; -+ } -+ if (msg->dir != SCM_PIPE_READ && msg->dir != SCM_PIPE_WRITE) { -+ uds_err("invalid pipe dir:%d", msg->dir); -+ return EVENT_ERR; -+ } -+ uds_log("pipe proxy event fd:%d pipe fd:%d dir:%d", evt->fd, msg->srcfd, msg->dir); -+ -+ if (msg->dir == SCM_PIPE_READ) { -+ evt->pipe = 1; -+ evt->peerfd = evt->fd; -+ evt->fd = msg->srcfd; -+ evt->handler = uds_event_pipe2tcp; -+ } else { -+ evt->pipe = 1; -+ evt->peerfd = msg->srcfd; -+ evt->handler = uds_event_tcp2pipe; -+ } -+ return EVENT_OK; -+} -+ -+int uds_event_remote_build(void *arg, int epfd, struct uds_event_global_var *p_event_var) -+{ -+ struct uds_event *evt = (struct uds_event *)arg; -+ struct uds_tcp2tcp *bdmsg = (struct uds_tcp2tcp *)p_event_var->iov_base; -+ struct uds_proxy_remote_conn_req *msg = (struct uds_proxy_remote_conn_req *)bdmsg->data; -+ int len; -+ int ret = EVENT_OK; -+ memset(p_event_var->iov_base, 0, p_event_var->iov_len); -+ len = recv(evt->fd, bdmsg, sizeof(struct uds_tcp2tcp), MSG_WAITALL); -+ if (len <= 0) { -+ uds_err("read no msg from sock:%d, len:%d", evt->fd, len); -+ return EVENT_ERR; -+ } -+ -+ switch (bdmsg->msgtype) { -+ case MSGCNTL_UDS: -+ ret = uds_build_connect2uds(evt, msg); -+ break; -+ case MSGCNTL_PIPE: -+ ret = uds_build_pipe_proxy(evt, (struct uds_stru_scm_pipe *)bdmsg->data); -+ break; -+ default: -+ uds_err("remote build not support msgtype %d now", bdmsg->msgtype); -+ break; -+ } -+ return ret; -+} -+ -+static inline mode_t uds_msg_file_mode(int fd) -+{ -+ struct stat st; -+ char path[32] = {0}; -+ if (fstat(fd, &st) != 0) { -+ uds_err("get fd:%d fstat failed, errstr:%s", fd, strerror(errno)); -+ } -+ if (S_ISFIFO(st.st_mode)) { -+ uds_log("fd:%d is fifo", fd); -+ } -+ -+ return st.st_mode; -+} -+ -+static int uds_msg_scm_regular_file(int scmfd, int tcpfd, struct uds_event_global_var *p_event_var) -+{ -+ int ret; -+ struct uds_tcp2tcp *p_msg = (struct uds_tcp2tcp *)p_event_var->buf; -+ struct uds_msg_scmrights *p_scmr = (struct uds_msg_scmrights *)&p_msg->data; -+ char *fdproc = calloc(1, UDS_PATH_MAX); -+ if (fdproc == NULL) { -+ uds_err("failed to calloc memory:%lx %lx", fdproc); -+ return EVENT_ERR; -+ } -+ sprintf(fdproc, "/proc/self/fd/%d", scmfd); -+ ret = readlink(fdproc, p_scmr->path, UDS_PATH_MAX); -+ if (ret < 0) { -+ uds_err("readlink:%s error, ret:%d, errstr:%s", fdproc, ret, strerror(errno)); -+ free(fdproc); -+ close(scmfd); -+ return EVENT_ERR; -+ } -+ free(fdproc); -+ p_scmr->flags = fcntl(scmfd, F_GETFL, 0); -+ if (p_scmr->flags < 0) { -+ uds_err("fcntl get flags failed:%d error:%s", p_scmr->flags, strerror(errno)); -+ close(scmfd); -+ return EVENT_ERR; -+ } -+ close(scmfd); -+ p_msg->msgtype = MSG_SCM_RIGHTS; -+ ret = write(tcpfd, p_msg, sizeof(struct uds_tcp2tcp) + sizeof(struct uds_msg_scmrights)); -+ if (ret <= 0) { -+ uds_err("send scm rights msg to tcp failed, ret:%d", ret); -+ return EVENT_ERR; -+ } -+ uds_log("scm rights msg send to tcp, fd:%d path:%s flags:%d", scmfd, p_scmr->path, p_scmr->flags); -+ return EVENT_OK; -+} -+ -+static int uds_msg_scm_fifo_file(int scmfd, int tcpfd, struct uds_event_global_var *p_event_var) -+{ -+#define FDPATH_LEN 32 -+ int ret; -+ struct uds_tcp2tcp *p_get = (struct uds_tcp2tcp *)p_event_var->buf; -+ struct uds_stru_scm_pipe *p_pipe = (struct uds_stru_scm_pipe *)p_get->data; -+ char path[FDPATH_LEN] = {0}; -+ struct stat st; -+ p_get->msgtype = MSG_SCM_PIPE; -+ p_get->msglen = sizeof(struct uds_stru_scm_pipe); -+ -+ sprintf(path, "/proc/self/fd/%d", scmfd); -+ lstat(path, &st); -+ if (st.st_mode & S_IRUSR) { -+ p_pipe->dir = SCM_PIPE_READ; -+ uds_log("scm rights recv read pipe fd:%d, mode:%o", scmfd, st.st_mode); -+ } else if (st.st_mode & S_IWUSR) { -+ p_pipe->dir = SCM_PIPE_WRITE; -+ uds_log("scm rights recv write pipe fd:%d, mode:%o", scmfd, st.st_mode); -+ } else { -+ uds_err("scm rights recv invalid pipe, mode:%o fd:%d", st.st_mode, scmfd); -+ return EVENT_ERR; -+ } -+ p_pipe->srcfd = scmfd; -+ ret = send(tcpfd, p_get, sizeof(struct uds_tcp2tcp) + sizeof(struct uds_stru_scm_pipe), 0); -+ if (ret <= 0) { -+ uds_err("send tar get msg failed, ret:%d errstr:%s", ret, strerror(errno)); -+ return EVENT_ERR; -+ } -+ return EVENT_OK; -+} -+ -+static int uds_msg_scmrights2tcp(struct cmsghdr *cmsg, int tcpfd, struct uds_event_global_var *p_event_var) -+{ -+ int scmfd; -+ mode_t mode; -+ -+ memset(p_event_var->buf, 0, p_event_var->buflen); -+ memcpy(&scmfd, CMSG_DATA(cmsg), sizeof(scmfd)); -+ if (scmfd <= 0) { -+ uds_err("recv invalid scm fd:%d", scmfd); -+ return EVENT_ERR; -+ } -+ -+ mode = uds_msg_file_mode(scmfd); -+ -+ switch (mode & S_IFMT) { -+ case S_IFREG: -+ uds_log("recv scmfd:%d from uds, is regular file", scmfd); -+ uds_msg_scm_regular_file(scmfd, tcpfd, p_event_var); -+ break; -+ case S_IFIFO: -+ uds_log("recv scmfd:%d from uds, is fifo", scmfd); -+ uds_msg_scm_fifo_file(scmfd, tcpfd, p_event_var); -+ break; -+ default: -+ uds_err("scm rights not support file mode:%o", mode); -+ break; -+ } -+ -+ return EVENT_OK; -+} -+ -+static int uds_msg_cmsg2tcp(struct msghdr *msg, struct uds_event *evt, struct uds_event_global_var *p_event_var) -+{ -+ int cnt = 0; -+ struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg); -+ while (cmsg != NULL) { -+ cnt ++; -+ uds_log("cmsg type:%d len:%d level:%d, tcpfd:%d", cmsg->cmsg_type, -+ cmsg->cmsg_len, cmsg->cmsg_level, evt->peer->fd); -+ switch (cmsg->cmsg_type) { -+ case SCM_RIGHTS: -+ uds_msg_scmrights2tcp(cmsg, evt->peer->fd, p_event_var); -+ break; -+ default: -+ uds_err("cmsg type:%d not support now", cmsg->cmsg_type); -+ break; -+ } -+ cmsg = CMSG_NXTHDR(msg, cmsg); -+ } -+ return cnt; -+} -+ -+static int uds_msg_scmfd_combine_msg(struct msghdr *msg, struct cmsghdr **cmsg, int *controllen, int fd) -+{ -+ struct cmsghdr *cnxt = NULL; -+ if (*cmsg == NULL) { -+ cnxt = CMSG_FIRSTHDR(msg); -+ } else { -+ cnxt = CMSG_NXTHDR(msg, *cmsg); -+ } -+ *cmsg = cnxt; -+ cnxt->cmsg_level = SOL_SOCKET; -+ cnxt->cmsg_type = SCM_RIGHTS; -+ cnxt->cmsg_len = CMSG_LEN(sizeof(fd)); -+ memcpy(CMSG_DATA(cnxt), &fd, sizeof(fd)); -+ *controllen = *controllen + cnxt->cmsg_len; -+ return EVENT_OK; -+} -+ -+static int uds_msg_scmright_send_fd(int sock, int fd) -+{ -+ char byte = 0; -+ struct iovec iov; -+ struct msghdr msg; -+ struct cmsghdr *cmsg; -+ char buf[CMSG_SPACE(sizeof(fd))]; -+ -+ // send at least one char -+ memset(&msg, 0, sizeof(msg)); -+ iov.iov_base = &byte; -+ iov.iov_len = 1; -+ msg.msg_iov = &iov; -+ msg.msg_iovlen = 1; -+ msg.msg_name = NULL; -+ msg.msg_namelen = 0; -+ -+ -+ msg.msg_control = buf; -+ msg.msg_controllen = sizeof(buf); -+ cmsg = CMSG_FIRSTHDR(&msg); -+ cmsg->cmsg_level = SOL_SOCKET; -+ cmsg->cmsg_type = SCM_RIGHTS; -+ cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); -+ // Initialize the payload -+ memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd)); -+ msg.msg_controllen = cmsg->cmsg_len; -+ -+ if (sendmsg(sock, &msg, 0) != iov.iov_len) -+ return -1; -+ return 0; -+} -+ -+static int uds_msg_cmsg2uds(struct uds_tcp2tcp *msg, struct uds_event *evt) -+{ -+ int scmfd = -1; -+ switch (msg->msgtype) { -+ case MSG_SCM_RIGHTS: { -+ struct uds_msg_scmrights *p_scmr = (struct uds_msg_scmrights *)&msg->data; -+ int ret; -+ int scmfd = open(p_scmr->path, p_scmr->flags); -+ if (scmfd < 0) { -+ uds_err("scm rights send fd failed, scmfd:%d path:%s flags:%d", scmfd, p_scmr->path, p_scmr->flags); -+ return -1; -+ } -+ uds_log("scm send fd:%d path:%s flags:%d", scmfd, p_scmr->path, p_scmr->flags); -+ break; -+ } -+ default: -+ uds_err("msg type:%d not support.", msg->msgtype); -+ return -1; -+ } -+ return scmfd; -+} -+ -+int uds_msg_tcp2uds_scm_pipe(struct uds_tcp2tcp *p_msg, struct uds_event *evt) -+{ -+ int scmfd; -+ int fd[SCM_PIPE_NUM]; -+ struct uds_stru_scm_pipe *p_pipe = (struct uds_stru_scm_pipe *)p_msg->data; -+ int len = recv(evt->fd, p_pipe, p_msg->msglen, MSG_WAITALL); -+ if (len <= 0) { -+ uds_err("recv data failed, len:%d", len); -+ return EVENT_DEL; -+ } -+ if (p_pipe->dir != SCM_PIPE_READ && p_pipe->dir != SCM_PIPE_WRITE) { -+ uds_err("scm pipe recv invalid pipe dir:%d, srcfd:%d", p_pipe->dir, p_pipe->srcfd); -+ return EVENT_ERR; -+ } -+ struct uds_conn_arg tcp = { -+ .cs = UDS_SOCKET_CLIENT, -+ }; -+ int ret; -+ if ((ret = uds_build_tcp_connection(&tcp)) < 0) { -+ uds_err("build tcp connection failed, return:%d", ret); -+ return EVENT_ERR; -+ } -+ if (pipe(fd) == -1) { -+ uds_err("pipe syscall error, strerr:%s", strerror(errno)); -+ return EVENT_ERR; -+ } -+ if (p_pipe->dir == SCM_PIPE_READ) { -+ uds_log("send read pipe:%d to peer:%d", fd[SCM_PIPE_READ], evt->peer->fd); -+ scmfd = fd[SCM_PIPE_READ]; -+ // read方向,proxy读取消息并转发,此代码处是远端,所以监听tcp换发给pipe write -+ uds_add_pipe_event(tcp.connfd, fd[SCM_PIPE_WRITE], uds_event_tcp2pipe, NULL); -+ } else { -+ uds_log("send write pipe:%d to peer:%d", fd[SCM_PIPE_WRITE], evt->peer->fd); -+ scmfd = fd[SCM_PIPE_WRITE]; -+ // write方向,proxy读取远端代理pipe消息并转发,此处是远端,所以监听pipe read并转发给tcp -+ uds_add_pipe_event(fd[SCM_PIPE_READ], tcp.connfd, uds_event_pipe2tcp, NULL); -+ } -+ -+ p_msg->msgtype = MSGCNTL_PIPE; -+ p_msg->msglen = sizeof(struct uds_stru_scm_pipe); -+ len = write(tcp.connfd, p_msg, sizeof(struct uds_tcp2tcp) + sizeof(struct uds_stru_scm_pipe)); -+ if (len <= 0) { -+ uds_err("send pipe msg failed, len:%d", len); -+ return EVENT_ERR; -+ } -+ uds_log("success to build pipe fd map, dir:%d srcfd:%d tcpfd:%d readfd:%d writefd:%d", -+ p_pipe->dir, p_pipe->srcfd, tcp.connfd, fd[SCM_PIPE_READ], fd[SCM_PIPE_WRITE]); -+ -+ return scmfd; -+} -+ -+int uds_event_tcp2pipe(void *arg, int epfd, struct uds_event_global_var *p_event_var) -+{ -+ struct uds_event *evt = (struct uds_event *)arg; -+ memset(p_event_var->iov_base, 0, p_event_var->iov_len); -+ int len = read(evt->fd, p_event_var->iov_base, p_event_var->iov_len); -+ if (len <= 0) { -+ uds_err("read from tcp failed, len:%d str:%s", len, strerror(errno)); -+ return EVENT_DEL; -+ } -+ -+ uds_log("tcp:%d to pipe:%d len:%d, buf:\n>>>>>>>\n%.*s\n<<<<<<<\n", evt->fd, evt->peerfd, len, len, p_event_var->iov_base); -+ int ret = write(evt->peerfd, p_event_var->iov_base, len); -+ if (ret <= 0) { -+ uds_err("write to pipe failed, fd:%d str:%s", evt->peerfd, strerror(errno)); -+ return EVENT_DEL; -+ } -+ return EVENT_OK; -+} -+ -+int uds_event_pipe2tcp(void *arg, int epfd, struct uds_event_global_var *p_event_var) -+{ -+ struct uds_event *evt = (struct uds_event *)arg; -+ memset(p_event_var->iov_base, 0, p_event_var->iov_len); -+ int len = read(evt->fd, p_event_var->iov_base, p_event_var->iov_len); -+ if (len <= 0) { -+ uds_err("read from pipe failed, len:%d str:%s", len, strerror(errno)); -+ return EVENT_DEL; -+ } -+ -+ uds_log("pipe:%d to tcp:%d len:%d, buf:\n>>>>>>>\n%.*s\n<<<<<<<\n", evt->fd, evt->peerfd, len, len, p_event_var->iov_base); -+ int ret = write(evt->peerfd, p_event_var->iov_base, len); -+ if (ret <= 0) { -+ uds_err("write to tcp failed, fd:%d str:%s", evt->peerfd, strerror(errno)); -+ return EVENT_DEL; -+ } -+ return EVENT_OK; -+ -+} -+ -+int uds_msg_tcp_end_msg(int sock) -+{ -+ struct uds_tcp2tcp end = {.msgtype = MSG_END, .msglen = 0,}; -+ int ret = write(sock, &end, sizeof(struct uds_tcp2tcp)); -+ if (ret <= 0) { -+ uds_err("write end msg failed, ret:%d fd:%d", ret, sock); -+ return EVENT_DEL; -+ } -+ return EVENT_OK; -+} -+ -+void uds_msg_init_event_buf(struct uds_event_global_var *p) -+{ -+ memset(p->iov_base, 0, p->iov_len); -+ memset(p->iov_base_send, 0, p->iov_sendlen); -+ memset(p->msg_control, 0, p->msg_controllen); -+ memset(p->msg_control_send, 0, p->msg_controlsendlen); -+ memset(p->buf, 0, p->buflen); -+ return; -+} -+ -+#define TEST_BUFLEN 256 -+int uds_event_uds2tcp(void *arg, int epfd, struct uds_event_global_var *p_event_var) -+{ -+ struct uds_event *evt = (struct uds_event *)arg; -+ struct iovec iov; -+ struct msghdr msg; -+ struct cmsghdr *cmsg; -+ int cmsgcnt = 0; -+ int len; -+ -+ memset(&msg, 0, sizeof(msg)); -+ iov.iov_base = p_event_var->iov_base + sizeof(struct uds_tcp2tcp); -+ iov.iov_len = p_event_var->iov_len - sizeof(struct uds_tcp2tcp); -+ msg.msg_iov = &iov; -+ msg.msg_iovlen = 1; -+ msg.msg_name = NULL; -+ msg.msg_namelen = 0; -+ -+ msg.msg_control = p_event_var->msg_control; -+ msg.msg_controllen = p_event_var->msg_controllen; -+ cmsg = CMSG_FIRSTHDR(&msg); -+ cmsg->cmsg_level = SOL_SOCKET; -+ cmsg->cmsg_len = p_event_var->msg_controllen; -+ -+ len = recvmsg(evt->fd, &msg, 0); -+ if (len == 0) { -+ uds_err("recvmsg error, return:%d", len); -+ uds_event_add_to_free(p_event_var, evt); -+ return EVENT_DEL; -+ } -+ if (len < 0) { -+ uds_err("recvmsg error return val:%d", len); -+ return EVENT_ERR; -+ } -+ cmsg = CMSG_FIRSTHDR(&msg); -+ if (cmsg != NULL) { -+ uds_log("recvmsg cmsg len:%d cmsglen:%d iovlen:%d iov:%s cmsglevel:%d cmsgtype:%d", -+ len, cmsg->cmsg_len, iov.iov_len, iov.iov_base, cmsg->cmsg_level, cmsg->cmsg_type); -+ cmsgcnt = uds_msg_cmsg2tcp(&msg, evt, p_event_var); -+ if (len - cmsgcnt == 0) -+ goto endmsg; -+ } -+ -+ struct uds_tcp2tcp *p_msg = (struct uds_tcp2tcp *)p_event_var->iov_base; -+ p_msg->msgtype = MSG_NORMAL; -+ p_msg->msglen = len; -+ int ret = write(evt->peer->fd, (void *)p_msg, p_msg->msglen + sizeof(struct uds_tcp2tcp)); -+ if (ret <= 0) { -+ uds_err("write to peer:%d failed, retcode:%d len:%d", evt->peer->fd, ret, len); -+ return EVENT_ERR; -+ } -+ -+ uds_log("write iov msg to tcp success, msgtype:%d ret:%d iovlen:%d recvlen:%d udsheadlen:%d msglen:%d msg:\n>>>>>>>\n%.*s\n<<<<<<<\n", -+ p_msg->msgtype, ret, iov.iov_len, len, sizeof(struct uds_tcp2tcp), p_msg->msglen, p_msg->msglen, p_msg->data); -+endmsg: -+ return uds_msg_tcp_end_msg(evt->peer->fd); -+} -+ -+int uds_event_tcp2uds(void *arg, int epfd, struct uds_event_global_var *p_event_var) -+{ -+#define MAX_FDS 64 -+ int fds[MAX_FDS] = {0}; -+ int fdnum = 0; -+ struct uds_event *evt = (struct uds_event *)arg; -+ struct uds_tcp2tcp *p_msg = (struct uds_tcp2tcp *)p_event_var->iov_base; -+ int ret; -+ int normal_msg_len = 0; -+ struct msghdr msg; -+ struct cmsghdr *cmsg = NULL; -+ struct iovec iov; -+ int msg_controllen = 0; -+ -+ memset(&msg, 0, sizeof(msg)); -+ iov.iov_base = p_event_var->iov_base_send; -+ iov.iov_len = 0; -+ msg.msg_iov = &iov; -+ msg.msg_iovlen = 1; -+ msg.msg_name = NULL; -+ msg.msg_namelen = 0; -+ msg.msg_control = p_event_var->msg_control_send; -+ msg.msg_controllen = p_event_var->msg_controlsendlen; -+ -+ while (1) { -+ int len = recv(evt->fd, p_msg, sizeof(struct uds_tcp2tcp), MSG_WAITALL); -+ if (len <= 0) { -+ uds_err("recv no msg maybe sock is closed, delete this tcp2uds event, len:%d.", len); -+ goto close_event; -+ } -+ uds_log("pmsg:%lx type:%d len:%d iov_base:%lx len:%d", p_msg, p_msg->msgtype, p_msg->msglen, p_event_var->iov_base, len); -+ if (p_msg->msgtype == MSG_END) { -+ break; -+ } -+ if (p_msg->msglen > p_event_var->iov_len - sizeof(struct uds_tcp2tcp) || p_msg->msglen <= 0) { -+ uds_err("pmsg len:%d is invalid, fd:%d peerfd:%d", p_msg->msglen, evt->fd, evt->peer->fd); -+ continue; -+ } -+ switch(p_msg->msgtype) { -+ case MSG_NORMAL: -+ if (normal_msg_len != 0) { -+ uds_err("normal msg repeat recv fd:%d", evt->fd); -+ goto err; -+ } -+ normal_msg_len = recv(evt->fd, p_event_var->iov_base_send, p_msg->msglen, MSG_WAITALL); -+ if (normal_msg_len <= 0) { -+ uds_err("recv msg error:%d fd:%d", len, evt->fd); -+ goto close_event; -+ } -+ iov.iov_len = normal_msg_len; -+ uds_log("recv normal msg len:%d str: \n>>>>>>>\n%.*s\n<<<<<<<", iov.iov_len, iov.iov_len, iov.iov_base); -+ break; -+ case MSG_SCM_RIGHTS: { -+ int len; -+ int scmfd; -+ struct uds_msg_scmrights *p_scm = (struct uds_msg_scmrights *) p_msg->data; -+ memset(p_scm->path, 0, sizeof(p_scm->path)); -+ // SCM RIGHTS msg proc -+ len = recv(evt->fd, p_msg->data, p_msg->msglen, MSG_WAITALL); -+ if (len <= 0) { -+ uds_err("recv data failed len:%d", p_msg->msglen); -+ return EVENT_DEL; -+ } -+ scmfd = uds_msg_cmsg2uds(p_msg, evt); -+ if (scmfd == -1) { -+ goto err; -+ } -+ fds[fdnum++] = scmfd; -+ uds_msg_scmfd_combine_msg(&msg, &cmsg, &msg_controllen, scmfd); -+ break; -+ } -+ case MSG_SCM_PIPE: { -+ int scmfd; -+ scmfd = uds_msg_tcp2uds_scm_pipe(p_msg, evt); -+ if (scmfd == EVENT_DEL) -+ goto close_event; -+ if (scmfd < 0) -+ goto err; -+ fds[fdnum++] = scmfd; -+ uds_msg_scmfd_combine_msg(&msg, &cmsg, &msg_controllen, scmfd); -+ break; -+ } -+ default: -+ uds_err("recv unsupport msg type:%d event fd:%d", p_msg->msgtype, evt->fd); -+ break; -+ } -+ } -+ if (msg_controllen == 0 && iov.iov_len == 0) -+ goto err; -+ msg.msg_controllen = msg_controllen; -+ if (iov.iov_len == 0) iov.iov_len = 1; -+ ret = sendmsg(evt->peer->fd, &msg, 0); -+ uds_log("evt:%d sendmsg len:%d, controllen:%d errno:%s", evt->fd, ret, msg_controllen, strerror(errno)); -+ for (int i = 0; i < fdnum; i++) { -+ close(fds[i]); -+ } -+ return EVENT_OK; -+err: -+ return EVENT_ERR; -+ -+close_event: -+ uds_event_add_to_free(p_event_var, evt); -+ return EVENT_DEL; -+} -+ -+int uds_diag_is_epoll_fd(int fd) -+{ -+ for (int i = 0; i < p_uds_var->work_thread_num; i++) { -+ if (fd == p_uds_var->efd[i]) -+ return 1; -+ } -+ return 0; -+} -+ -+void uds_diag_list_fd(char *buf, int len) -+{ -+#define FDPATH_LEN 32 -+ int pos = 0; -+ char path[32] = {0}; -+ DIR *dir = NULL; -+ struct dirent *entry; -+ dir = opendir("/proc/self/fd/"); -+ if (dir == NULL) { -+ uds_err("open path:/proc/self/fd/ failed"); -+ return; -+ } -+ while (entry = readdir(dir)) { -+ int fd = atoi(entry->d_name); -+ char fdpath[FDPATH_LEN]; -+ char link[FDPATH_LEN]; -+ int ret; -+ if (fd <= 2 || uds_diag_is_epoll_fd(fd)) -+ continue; -+ memset(fdpath, 0, FDPATH_LEN); -+ memset(link, 0, FDPATH_LEN); -+ sprintf(fdpath, "/proc/self/fd/%d", fd); -+ ret = readlink(fdpath, link, FDPATH_LEN); -+ pos += sprintf(&buf[pos], "+ fd:%s type:%u link:%s\n", entry->d_name, entry->d_type, link); -+ } -+ closedir(dir); -+ return; -+} -+ -+int uds_diag_string(char *buf, int len) -+{ -+ int pos = 0; -+ memset(buf, 0, len); -+ pos = sprintf(buf, "+-----------------------------Unix Proxy Diagnostic information-------------------------+\n"); -+ pos += sprintf(&buf[pos], "+ Thread nums:%d\n", p_uds_var->work_thread_num); -+ for (int i = 0; i < p_uds_var->work_thread_num; i++) { -+ pos += sprintf(&buf[pos], "+ Thread %d events count:%d\n", i+1, p_uds_var->work_thread[i].info.events); -+ } -+ pos += sprintf(&buf[pos], "+ Log level:%s\n", p_uds_var->logstr[p_uds_var->loglevel]); -+ strcat(buf, "+---------------------------------------------------------------------------------------+\n"); -+ return strlen(buf); -+} -+ -+// DIAG INFO -+int uds_event_diag_info(void *arg, int epfd, struct uds_event_global_var *p_event_var) -+{ -+ int connfd; -+ int len; -+ int ret; -+ struct uds_event *evt = (struct uds_event *)arg; -+ if (evt == NULL) { -+ uds_err("param is invalid."); -+ return EVENT_ERR; -+ } -+ connfd = uds_sock_step_accept(evt->fd, AF_UNIX); -+ if (connfd <= 0) { -+ uds_err("conn fd error:%d", connfd); -+ return EVENT_ERR; -+ } -+ -+ uds_log("diag accept an new connection to send diag info, fd:%d", connfd); -+ len = uds_diag_string(p_event_var->iov_base, p_event_var->iov_len); -+ ret = send(connfd, p_event_var->iov_base, len, 0); -+ if (ret <= 0) { -+ uds_err("send diag info error, ret:%d len:%d", ret, len); -+ } -+ close(connfd); -+ return EVENT_OK; -+} -+ -+#define UDS_LOG_STR(level) (level < 0 || level >= UDS_LOG_MAX) ? p_uds_var->logstr[UDS_LOG_MAX] : p_uds_var->logstr[level] -+int uds_event_debug_level(void *arg, int epfd, struct uds_event_global_var *p_event_var) -+{ -+ int connfd; -+ int len; -+ int ret; -+ int cur; -+ struct uds_event *evt = (struct uds_event *)arg; -+ if (evt == NULL) { -+ uds_err("param is invalid."); -+ return EVENT_ERR; -+ } -+ connfd = uds_sock_step_accept(evt->fd, AF_UNIX); -+ if (connfd <= 0) { -+ uds_err("conn fd error:%d", connfd); -+ return EVENT_ERR; -+ } -+ -+ cur = p_uds_var->loglevel; -+ if (cur + 1 < UDS_LOG_MAX) { -+ p_uds_var->loglevel += 1; -+ } else { -+ p_uds_var->loglevel = UDS_LOG_NONE; -+ } -+ -+ uds_log("debug level accept a new connection, current level:%s change to:%s", UDS_LOG_STR(cur), UDS_LOG_STR(p_uds_var->loglevel)); -+ -+ len = sprintf(p_event_var->iov_base, "+---------------UDS LOG LEVEL UPDATE--------------+\n" -+ "+ Log level is:%s before, now change to :%s.\n" -+ "+-------------------------------------------------+\n", UDS_LOG_STR(cur), UDS_LOG_STR(p_uds_var->loglevel)); -+ -+ ret = send(connfd, p_event_var->iov_base, len, 0); -+ if (ret <= 0) { -+ uds_err("send debug level info error, ret:%d len:%d", ret, len); -+ } -+ close(connfd); -+ return EVENT_OK; -+} -diff --git a/qtfs/ipc/uds_event.h b/qtfs/ipc/uds_event.h -new file mode 100644 -index 0000000..a52bf67 ---- /dev/null -+++ b/qtfs/ipc/uds_event.h -@@ -0,0 +1,64 @@ -+#ifndef __QTFS_UDS_EVENT_H__ -+#define __QTFS_UDS_EVENT_H__ -+ -+#define UDS_EVENT_BUFLEN 4096 -+#define UDS_PATH_MAX 1024 -+ -+enum EVENT_RETCODE { -+ EVENT_OK = 0, -+ EVENT_ERR = -1, -+ EVENT_DEL = -2, // del this event after return -+}; -+ -+enum TCP2TCP_TYPE { -+ MSG_NORMAL = 0xa5a5, // 消息类型从特殊数字开始,防止误识别消息 -+ MSG_SCM_RIGHTS, -+ MSG_SCM_CREDENTIALS, // unix domain 扩展消息,预留 -+ MSG_SCM_SECURITY, // unix domain 扩展消息,预留 -+ MSG_GET_TARGET, // 控制消息,用于获取对端的target fd -+ MSG_SCM_PIPE, // 使用SCM传递了一个pipe -+ MSG_END, // tcp消息的结束体 -+}; -+ -+enum TCPCNTL_TYPE { -+ MSGCNTL_UDS = 1, // uds代理模式 -+ MSGCNTL_PIPE, // pipe匿名管道代理模式 -+}; -+ -+// 因为要区分SCM_RIGHTS和普通消息,TCP到TCP需要有一个协议头 -+struct uds_tcp2tcp { -+ int msgtype; -+ int msglen; // len of data -+ char data[0]; -+}; -+ -+struct uds_msg_scmrights { -+ int flags; // open flags -+ char path[UDS_PATH_MAX]; -+}; -+ -+enum { -+ SCM_PIPE_READ = 0, -+ SCM_PIPE_WRITE, -+ SCM_PIPE_NUM, -+}; -+ -+struct uds_stru_scm_pipe { -+ int dir; // 0: send read filedes; 1: send write filedes -+ // proxy通过scm rights接收到员pipe fd,后面消息回来时事件 -+ // 会发生变化,所以需要回消息时带上,才能建立关联 -+ int srcfd; -+}; -+ -+int uds_event_uds_listener(void *arg, int epfd, struct uds_event_global_var *p_event_var); -+int uds_event_tcp_listener(void *arg, int epfd, struct uds_event_global_var *p_event_var); -+int uds_event_diag_info(void *arg, int epfd, struct uds_event_global_var *p_event_var); -+int uds_event_debug_level(void *arg, int epfd, struct uds_event_global_var *p_event_var); -+int uds_event_pre_handler(struct uds_event *evt); -+int uds_event_pre_hook(struct uds_event_global_var *p_event_var); -+int uds_event_post_hook(struct uds_event_global_var *p_event_var); -+int uds_event_module_init(struct uds_event_global_var *p_event_var); -+void uds_event_module_fini(struct uds_event_global_var *p); -+ -+#endif -+ -diff --git a/qtfs/ipc/uds_main.c b/qtfs/ipc/uds_main.c -new file mode 100644 -index 0000000..b479a60 ---- /dev/null -+++ b/qtfs/ipc/uds_main.c -@@ -0,0 +1,556 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "../comm.h" -+#include "uds_main.h" -+#include "uds_event.h" -+ -+struct uds_global_var g_uds_var = {.logstr = {"NONE", "ERROR", "INFO", "UNKNOWN"}}; -+struct uds_global_var *p_uds_var = &g_uds_var; -+struct uds_event_global_var *g_event_var = NULL; -+ -+struct uds_event *uds_alloc_event() -+{ -+ struct uds_event *p = (struct uds_event *)malloc(sizeof(struct uds_event)); -+ if (p == NULL) { -+ uds_err("malloc failed."); -+ return NULL; -+ } -+ memset(p, 0, sizeof(struct uds_event)); -+ return p; -+} -+ -+int uds_event_insert(int efd, struct uds_event *event) -+{ -+ struct epoll_event evt; -+ evt.data.ptr = (void *)event; -+ evt.events = EPOLLIN; -+ if (-1 == epoll_ctl(efd, EPOLL_CTL_ADD, event->fd, &evt)) { -+ uds_err("epoll ctl add fd:%d event failed.", event->fd); -+ return -1; -+ } -+ return 0; -+} -+ -+int uds_event_suspend(int efd, struct uds_event *event) -+{ -+ int ret = epoll_ctl(efd, EPOLL_CTL_DEL, event->fd, NULL); -+ if (ret != 0) { -+ uds_err("failed to suspend fd:%d.", event->fd); -+ return -1; -+ } -+ return 0; -+} -+ -+int uds_event_delete(int efd, int fd) -+{ -+ int ret = epoll_ctl(efd, EPOLL_CTL_DEL, fd, NULL); -+ if (ret != 0) { -+ uds_err("failed to delete event fd:%d.", fd); -+ } else { -+ uds_log("event fd:%d deleted.", fd); -+ } -+ close(fd); -+ return ret; -+} -+ -+void uds_main_loop(int efd, struct uds_thread_arg *arg) -+{ -+ int n = 0; -+ int ret; -+ struct uds_event *udsevt; -+ struct epoll_event *evts = NULL; -+ struct uds_event_global_var *p_event_var = arg->p_event_var; -+ if (p_event_var == NULL) { -+ uds_err("event variable invalid."); -+ return; -+ } -+ -+ evts = calloc(UDS_EPOLL_MAX_EVENTS, sizeof(struct epoll_event)); -+ if (evts == NULL) { -+ uds_err("init calloc evts failed."); -+ return; -+ } -+ if (uds_event_module_init(p_event_var) == EVENT_ERR) { -+ uds_err("uds event module init failed, main loop not run."); -+ return; -+ } -+#ifdef QTFS_SERVER -+ extern int engine_run; -+ while (engine_run) { -+#else -+ while (1) { -+#endif -+ n = epoll_wait(efd, evts, UDS_EPOLL_MAX_EVENTS, 1000); -+ if (n == 0) -+ continue; -+ if (n < 0) { -+ uds_err("epoll wait return errcode:%d", n); -+ continue; -+ } -+ arg->info.events += n; -+ uds_event_pre_hook(p_event_var); -+ for (int i = 0; i < n; i++) { -+ udsevt = (struct uds_event *)evts[i].data.ptr; -+ uds_log("event fd:%d events:%d tofree:%d", udsevt->fd, evts[i].events, udsevt->tofree); -+ if (udsevt->handler == NULL) { -+ uds_err("bad event, fd:%d handler is NULL.", udsevt->fd); -+ continue; -+ } -+ // 预检查失败择不执行handler -+ if (uds_event_pre_handler(udsevt) == EVENT_ERR) { -+ continue; -+ } -+ ret = udsevt->handler(udsevt, efd, p_event_var); -+ // 此处释放当前事件,peer事件需要handler里面释放 -+ if (ret == EVENT_DEL) { -+ uds_del_event(udsevt); -+ } -+ } -+ uds_event_post_hook(p_event_var); -+ } -+ uds_log("main loop exit."); -+ uds_event_module_fini(p_event_var); -+ return; -+} -+ -+int uds_build_tcp_connection(struct uds_conn_arg *arg) -+{ -+ const int sock_max_conn_num = 1024; -+ -+ if (arg->cs > UDS_SOCKET_SERVER) { -+ uds_err("cs type %d is error.", arg->cs); -+ return -1; -+ } -+ struct sockaddr_in sock_addr = { -+ .sin_family = AF_INET, -+ }; -+ int sock_fd = socket(AF_INET, SOCK_STREAM, 0); -+ -+ if (sock_fd < 0) { -+ uds_err("As %s failed, socket fd: %d, err:%s.", -+ (arg->cs == UDS_SOCKET_CLIENT) ? "client" : "server", -+ sock_fd, strerror(errno)); -+ return -1; -+ } -+ arg->sockfd = sock_fd; -+ -+ if (arg->cs == UDS_SOCKET_SERVER) { -+ sock_addr.sin_port = htons(p_uds_var->tcp.port); -+ sock_addr.sin_addr.s_addr = inet_addr(p_uds_var->tcp.addr); -+ if (bind(sock_fd, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) < 0) { -+ uds_err("As server failed, bind error, err:%s.", -+ strerror(errno)); -+ goto close_and_return; -+ } -+ if (listen(sock_fd, sock_max_conn_num) < 0) { -+ uds_err("As server listen failed, err:%s.", strerror(errno)); -+ goto close_and_return; -+ } -+ } else { -+ sock_addr.sin_port = htons(p_uds_var->tcp.peerport); -+ sock_addr.sin_addr.s_addr = inet_addr(p_uds_var->tcp.peeraddr); -+ if (connect(arg->sockfd, (struct sockaddr *)&sock_addr, sizeof(struct sockaddr_in)) < 0) { -+ goto close_and_return; -+ } -+ arg->connfd = sock_fd; -+ uds_log("Connect to server successed, ip:%s port:%u", p_uds_var->tcp.peeraddr, p_uds_var->tcp.peerport); -+ } -+ -+ return 0; -+close_and_return: -+ close(sock_fd); -+ return -1; -+} -+ -+int uds_build_unix_connection(struct uds_conn_arg *arg) -+{ -+ const int sock_max_conn_num = 5; -+ if (arg->cs > UDS_SOCKET_SERVER) { -+ uds_err("cs type %d is error.", arg->cs); -+ return -1; -+ } -+ struct sockaddr_un sock_addr = { -+ .sun_family = AF_UNIX, -+ }; -+ int sock_fd = socket(AF_UNIX, arg->udstype, 0); -+ -+ if (sock_fd < 0) { -+ uds_err("As %s failed, socket fd: %d, err:%s.", -+ (arg->cs == UDS_SOCKET_CLIENT) ? "client" : "server", -+ sock_fd, strerror(errno)); -+ return -1; -+ } -+ strncpy(sock_addr.sun_path, arg->sun_path, sizeof(sock_addr.sun_path)); -+ arg->sockfd = sock_fd; -+ -+ if (arg->cs == UDS_SOCKET_SERVER) { -+ unlink(sock_addr.sun_path); -+ if (bind(sock_fd, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) < 0) { -+ uds_err("As server failed, bind error, err:%s.", -+ strerror(errno)); -+ goto close_and_return; -+ } -+ if (listen(sock_fd, sock_max_conn_num) < 0) { -+ uds_err("As server listen failed, err:%s.", strerror(errno)); -+ goto close_and_return; -+ } -+ } else { -+ if (connect(arg->sockfd, (struct sockaddr *)&sock_addr, sizeof(struct sockaddr_un)) < 0) { -+ goto close_and_return; -+ } -+ arg->connfd = sock_fd; -+ uds_log("Connect to server successed, sun path:%s", arg->sun_path); -+ } -+ -+ return 0; -+close_and_return: -+ uds_log("close sockfd:%d and return", sock_fd); -+ close(sock_fd); -+ return -1; -+ -+} -+ -+int uds_sock_step_accept(int sock_fd, int family) -+{ -+ struct sockaddr_in in_addr; -+ struct sockaddr_un un_addr; -+ socklen_t len = (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_un); -+ int connfd; -+ if (family == AF_INET) { -+ connfd = accept(sock_fd, (struct sockaddr *)&in_addr, &len); -+ } else { -+ connfd = accept(sock_fd, (struct sockaddr *)&un_addr, &len); -+ } -+ if (connfd < 0) { -+ uds_err("Accept error:%d, err:%s.", connfd, strerror(errno)); -+ return connfd; -+ } -+ if (family == AF_INET) { -+ uds_log("Accept success, ip:%s, port:%u", -+ inet_ntoa(in_addr.sin_addr), -+ ntohs(in_addr.sin_port)); -+ } else { -+ uds_log("Accept success, sun path:%s", un_addr.sun_path); -+ } -+ return connfd; -+} -+ -+struct uds_event *uds_add_event(int fd, struct uds_event *peer, int (*handler)(void *, int, struct uds_event_global_var *), void *priv) -+{ -+ struct uds_event *newevt = uds_alloc_event(); -+ int hash = fd % p_uds_var->work_thread_num; -+ if (newevt == NULL || p_uds_var->efd[hash] <= 0) { -+ uds_err("alloc event failed, efd:%d hash:%d", p_uds_var->efd[hash], hash); -+ return NULL; -+ } -+ -+ newevt->fd = fd; -+ newevt->peer = peer; // 如果tcp回应,消息转回uds这个fd -+ newevt->handler = handler; -+ newevt->priv = priv; -+ newevt->tofree = 0; -+ uds_event_insert(p_uds_var->efd[hash], newevt); -+ return newevt; -+} -+ -+struct uds_event *uds_add_pipe_event(int fd, int peerfd, int (*handler)(void *, int, struct uds_event_global_var *), void *priv) -+{ -+ int hash = fd % p_uds_var->work_thread_num; -+ struct uds_event *newevt = uds_alloc_event(); -+ if (newevt == NULL || p_uds_var->efd[hash] <= 0) { -+ uds_err("alloc event failed, efd:%d", p_uds_var->efd[hash]); -+ return NULL; -+ } -+ -+ newevt->fd = fd; -+ newevt->peerfd = peerfd; // 如果tcp回应,消息转回uds这个fd -+ newevt->handler = handler; -+ newevt->priv = priv; -+ newevt->tofree = 0; -+ newevt->pipe = 1; -+ uds_event_insert(p_uds_var->efd[hash], newevt); -+ return newevt; -+} -+ -+void uds_del_event(struct uds_event *evt) -+{ -+ int hash = evt->fd % p_uds_var->work_thread_num; -+ if (evt->pipe == 1 &&evt->peerfd != -1) { -+ // pipe是单向,peerfd没有epoll事件,所以直接关闭 -+ close(evt->peerfd); -+ evt->peerfd = -1; -+ } -+ uds_event_delete(p_uds_var->efd[hash], evt->fd); -+ free(evt); -+ return; -+} -+ -+void uds_thread_diag_init(struct uds_thread_info *info) -+{ -+ info->events = 0; -+ info->fdnum = 0; -+} -+ -+void *uds_proxy_thread(void *arg) -+{ -+ struct uds_thread_arg *parg = (struct uds_thread_arg *)arg; -+ uds_thread_diag_init(&parg->info); -+ uds_main_loop(parg->efd, parg); -+ return NULL; -+} -+ -+struct uds_event *uds_init_unix_listener(const char *addr, int (*handler)(void *, int, struct uds_event_global_var *)) -+{ -+ struct uds_event *udsevt; -+ struct uds_conn_arg arg; -+ struct uds_conn_arg *parg = &arg; -+ -+ parg->cs = UDS_SOCKET_SERVER; -+ strncpy(parg->sun_path, addr, sizeof(parg->sun_path)); -+ parg->udstype = SOCK_STREAM; -+ if (uds_build_unix_connection(parg) != 0) -+ return NULL; -+ udsevt = uds_add_event(parg->sockfd, NULL, handler, NULL); -+ if (udsevt == NULL) { -+ uds_err("add unix listener event failed."); -+ return NULL; -+ } -+ return udsevt; -+} -+ -+struct uds_event *uds_init_tcp_listener() -+{ -+ struct uds_event *tcpevt; -+ struct uds_conn_arg arg; -+ struct uds_conn_arg *parg = &arg; -+ parg->cs = UDS_SOCKET_SERVER; -+ if (uds_build_tcp_connection(parg) != 0) -+ return NULL; -+ -+ tcpevt = uds_add_event(parg->sockfd, NULL, uds_event_tcp_listener, NULL); -+ if (tcpevt == NULL) -+ return NULL; -+ return tcpevt; -+} -+ -+void uds_thread_create() -+{ -+ struct uds_conn_arg arg; -+ struct uds_conn_arg *parg = &arg; -+ struct uds_event *udsevt; -+ struct uds_event *tcpevt; -+ struct uds_event *diagevt; -+ struct uds_event *logevt; -+ int efd; -+ -+ for (int i = 0; i < p_uds_var->work_thread_num; i++) { -+ efd = epoll_create1(0); -+ if (efd == -1) { -+ uds_err("epoll create1 failed, i:%d.", i); -+ return; -+ } -+ p_uds_var->efd[i] = efd; -+ } -+ -+ if ((udsevt = uds_init_unix_listener(UDS_BUILD_CONN_ADDR, uds_event_uds_listener)) == NULL) -+ return; -+ -+ if ((tcpevt = uds_init_tcp_listener()) == NULL) -+ goto end; -+ -+ if ((diagevt = uds_init_unix_listener(UDS_DIAG_ADDR, uds_event_diag_info)) == NULL) -+ goto end1; -+ -+ if ((logevt = uds_init_unix_listener(UDS_LOGLEVEL_UPD, uds_event_debug_level)) == NULL) -+ goto end2; -+ -+ do { -+ pthread_t *thrd = (pthread_t *)malloc(sizeof(pthread_t) * p_uds_var->work_thread_num); -+ struct uds_thread_arg *work_thread; -+ if (thrd == NULL) { -+ uds_err("thread info malloc failed."); -+ break; -+ } -+ work_thread = (struct uds_thread_arg *)malloc(sizeof(struct uds_thread_arg *) * p_uds_var->work_thread_num); -+ if (work_thread == NULL) { -+ uds_err("thread arg malloc failed."); -+ free(thrd); -+ break; -+ } -+ -+ for (int i = 0; i < p_uds_var->work_thread_num; i++) { -+ p_uds_var->work_thread[i].p_event_var = &g_event_var[i]; -+ p_uds_var->work_thread[i].efd = p_uds_var->efd[i]; -+ (void)pthread_create(&thrd[i], NULL, uds_proxy_thread, &p_uds_var->work_thread[i]); -+ } -+ p_uds_var->loglevel = UDS_LOG_NONE; -+ for (int i = 0; i < p_uds_var->work_thread_num; i++) -+ pthread_join(thrd[i], NULL); -+ free(thrd); -+ free(work_thread); -+ } while(0); -+end2: -+ uds_del_event(diagevt); -+end1: -+ uds_del_event(tcpevt); -+end: -+ uds_del_event(udsevt); -+ for (int i = 0; i < p_uds_var->work_thread_num; i++) -+ close(p_uds_var->efd[i]); -+ -+ return; -+} -+ -+int uds_set_pid() -+{ -+ int fd = -1; -+ if (access(QTFS_CLIENT_DEV, 0) == 0) { -+ fd = open(QTFS_CLIENT_DEV, O_RDONLY | O_NONBLOCK); -+ if (fd < 0) -+ goto open_failed; -+ goto set; -+ } -+ if (access(QTFS_SERVER_DEV, 0) == 0) { -+ fd = open(QTFS_SERVER_DEV, O_RDONLY | O_NONBLOCK); -+ if (fd < 0) -+ goto open_failed; -+ goto set; -+ } -+ uds_err("qtfs dev(<%s> or <%s>) both not exist", QTFS_CLIENT_DEV, QTFS_SERVER_DEV); -+ return EVENT_ERR; -+ -+open_failed: -+ uds_err("open %s failed, ret:%d", QTFS_CLIENT_DEV, fd); -+ return EVENT_ERR; -+ -+set: -+ do { -+ int pid = getpid(); -+ int ret = ioctl(fd, QTFS_IOCTL_UDS_PROXY_PID, &pid); -+ if (ret < 0) { -+ uds_err("ioctl failed to set pid:%d ret:%d", pid, ret); -+ return EVENT_ERR; -+ } -+ uds_log("set proxy pid:%d to qtfs successed.", pid); -+ } while (0); -+ close(fd); -+ return EVENT_OK; -+} -+ -+int uds_env_prepare() -+{ -+ DIR *dir; -+ if (access(UDS_BUILD_CONN_ADDR, 0) == 0) -+ return EVENT_OK; -+ -+ if ((dir = opendir(UDS_BUILD_CONN_DIR)) == NULL) { -+ if (mkdir(UDS_BUILD_CONN_DIR, 0755) < 0) { -+ uds_err("mkdir %s failed.", UDS_BUILD_CONN_DIR); -+ } -+ } else { -+ closedir(dir); -+ } -+ int fd = open(UDS_BUILD_CONN_ADDR, O_RDONLY|O_CREAT, 0700); -+ if (fd < 0) { -+ uds_err("create file:%s failed.", UDS_BUILD_CONN_ADDR); -+ return EVENT_ERR; -+ } -+ uds_log("success to create %s.", UDS_BUILD_CONN_ADDR); -+ close(fd); -+ return EVENT_OK; -+} -+ -+static void uds_sig_pipe(int signum) -+{ -+ uds_log("uds proxy recv sigpipe and ignore"); -+} -+ -+void uds_helpinfo(char *argv[]) -+{ -+ uds_err("Usage:"); -+ uds_err(" %s .", argv[0]); -+ uds_err("Param:"); -+ uds_err(" - server ip address"); -+ uds_err(" - port number"); -+ uds_err(" - peer address"); -+ uds_err(" - peer port"); -+ return; -+} -+ -+/* -+ * uds跨主机协同主程序,设计成镜像的,每一端2个线程:send thread、recv thread -+ * 在server侧线程由原engine拉起,在client侧新起一个engine进程 -+ */ -+#ifdef QTFS_SERVER -+int uds_proxy_main(int argc, char *argv[]) -+#else -+int main(int argc, char *argv[]) -+#endif -+{ -+ p_uds_var->loglevel = UDS_LOG_INFO; -+#define ARG_NUM 6 -+ if (argc != ARG_NUM) { -+ uds_helpinfo(argv); -+ return -1; -+ } -+ if (uds_set_pid() != EVENT_OK) { -+ uds_err("proxy failed to set pid."); -+ return -1; -+ } -+ if (uds_env_prepare() != EVENT_OK) { -+ uds_err("proxy prepare environment failed."); -+ return -1; -+ } -+ signal(SIGPIPE, uds_sig_pipe); -+ p_uds_var->work_thread_num = atoi(argv[1]); -+ if (p_uds_var->work_thread_num <= 0 || p_uds_var->work_thread_num > UDS_WORK_THREAD_MAX) { -+ uds_err("work thread num:%d is too large.(must small or equal than %d)", p_uds_var->work_thread_num, UDS_WORK_THREAD_MAX); -+ return -1; -+ } -+ p_uds_var->efd = (int *)malloc(sizeof(int) * p_uds_var->work_thread_num); -+ if (p_uds_var->efd == NULL) { -+ uds_err("efd malloc failed, num:%d", p_uds_var->work_thread_num); -+ return -1; -+ } -+ -+ p_uds_var->work_thread = (struct uds_thread_arg *)malloc(sizeof(struct uds_thread_arg) * p_uds_var->work_thread_num); -+ if (p_uds_var->work_thread == NULL) { -+ uds_err("work thread var malloc failed."); -+ return -1; -+ } -+ p_uds_var->tcp.port = atoi(argv[3]); -+ strncpy(p_uds_var->tcp.addr, argv[2], 20); -+ p_uds_var->tcp.peerport = atoi(argv[5]); -+ strncpy(p_uds_var->tcp.peeraddr, argv[4], 20); -+ -+ uds_log("uds proxy param thread num:%d ip:%s port:%u peerip:%s port:%u", -+ p_uds_var->work_thread_num, p_uds_var->tcp.addr, p_uds_var->tcp.port, -+ p_uds_var->tcp.peeraddr, p_uds_var->tcp.peerport); -+ g_event_var = (struct uds_event_global_var *)malloc(sizeof(struct uds_event_global_var) * p_uds_var->work_thread_num); -+ if (g_event_var == NULL) { -+ uds_err("event variable malloc failed"); -+ return -1; -+ } -+ uds_thread_create(); -+ -+ return 0; -+} -diff --git a/qtfs/ipc/uds_main.h b/qtfs/ipc/uds_main.h -new file mode 100644 -index 0000000..793cd2f ---- /dev/null -+++ b/qtfs/ipc/uds_main.h -@@ -0,0 +1,141 @@ -+#ifndef __QTFS_UDS_MAIN_H__ -+#define __QTFS_UDS_MAIN_H__ -+ -+#include -+ -+#include "uds_module.h" -+ -+#define UDS_EPOLL_MAX_EVENTS 64 -+#define UDS_WORK_THREAD_MAX 64 -+ -+extern struct uds_global_var *p_uds_var; -+ -+enum { -+ UDS_LOG_NONE, -+ UDS_LOG_ERROR, -+ UDS_LOG_INFO, -+ UDS_LOG_MAX, -+}; -+ -+#define uds_log(info, ...) \ -+ if (p_uds_var->loglevel >= UDS_LOG_INFO) {\ -+ time_t t; \ -+ struct tm *p; \ -+ time(&t); \ -+ p = localtime(&t); \ -+ printf("[%d/%02d/%02d %02d:%02d:%02d][LOG:%s:%3d]"info"\n", \ -+ p->tm_year + 1900, p->tm_mon+1, p->tm_mday, \ -+ p->tm_hour, p->tm_min, p->tm_sec, __func__, __LINE__, ##__VA_ARGS__); \ -+ } -+ -+#define uds_log2(info, ...) \ -+ if (p_uds_var->loglevel >= UDS_LOG_INFO) {\ -+ time_t t; \ -+ struct tm *p; \ -+ time(&t); \ -+ p = localtime(&t); \ -+ printf("[%d/%02d/%02d %02d:%02d:%02d][LOG:%s:%3d]"info"\n", \ -+ p->tm_year + 1900, p->tm_mon+1, p->tm_mday, \ -+ p->tm_hour, p->tm_min, p->tm_sec, __func__, __LINE__, ##__VA_ARGS__); \ -+ } -+ -+#define uds_err(info, ...) \ -+ if (p_uds_var->loglevel >= UDS_LOG_ERROR) {\ -+ time_t t; \ -+ struct tm *p; \ -+ time(&t); \ -+ p = localtime(&t); \ -+ printf("[%d/%02d/%02d %02d:%02d:%02d][ERROR:%s:%3d]"info"\n", \ -+ p->tm_year + 1900, p->tm_mon+1, p->tm_mday, \ -+ p->tm_hour, p->tm_min, p->tm_sec, __func__, __LINE__, ##__VA_ARGS__); \ -+ } -+ -+enum { -+ UDS_THREAD_EPWAIT = 1, // epoll wait status -+}; -+struct uds_thread_info { -+ int fdnum; -+ -+ int events; -+ int status; -+}; -+ -+struct uds_event_global_var { -+ int cur; -+ struct uds_event *tofree[UDS_EPOLL_MAX_EVENTS]; -+ char *msg_control; -+ int msg_controllen; -+ char *msg_control_send; -+ int msg_controlsendlen; -+ char *iov_base; -+ int iov_len; -+ char *iov_base_send; -+ int iov_sendlen; -+ char *buf; -+ int buflen; -+}; -+ -+struct uds_event { -+ int fd; /* 本事件由这个fd触发 */ -+ unsigned int tofree : 1, /* 1--in to free list; 0--not */ -+ pipe : 1, // this is a pipe event -+ reserved : 30; -+ union { -+ struct uds_event *peer; /* peer event */ -+ int peerfd; // scm pipe 场景单向导通,只需要一个fd即可 -+ }; -+ int (*handler)(void *, int, struct uds_event_global_var *); /* event处理函数 */ -+ void *priv; // private data -+ char cpath[UDS_SUN_PATH_LEN]; -+ char spath[UDS_SUN_PATH_LEN]; -+}; -+ -+ -+struct uds_thread_arg { -+ int efd; -+ struct uds_event_global_var *p_event_var; -+ struct uds_thread_info info; -+}; -+ -+struct uds_global_var { -+ int work_thread_num; -+ int *efd; -+ struct uds_thread_arg *work_thread; -+ int loglevel; -+ char *logstr[UDS_LOG_MAX + 1]; -+ struct _tcp { -+ char addr[20]; -+ unsigned short port; -+ char peeraddr[20]; -+ unsigned short peerport; -+ } tcp; -+ struct _uds { -+ char sun_path[UDS_SUN_PATH_LEN]; -+ } uds; -+}; -+enum uds_cs { -+ UDS_SOCKET_CLIENT = 1, -+ UDS_SOCKET_SERVER, -+}; -+ -+struct uds_conn_arg { -+ int cs; // client(1) or server(2) -+ -+ int udstype; // DGRAM or STREAM -+ char sun_path[UDS_SUN_PATH_LEN]; -+ int sockfd; -+ int connfd; -+}; -+ -+struct uds_event *uds_add_event(int fd, struct uds_event *peer, int (*handler)(void *, int, struct uds_event_global_var *), void *priv); -+struct uds_event *uds_add_pipe_event(int fd, int peerfd, int (*handler)(void *, int, struct uds_event_global_var *), void *priv); -+int uds_sock_step_accept(int sockFd, int family); -+int uds_build_tcp_connection(struct uds_conn_arg *arg); -+int uds_build_unix_connection(struct uds_conn_arg *arg); -+void uds_del_event(struct uds_event *evt); -+int uds_event_suspend(int efd, struct uds_event *event); -+int uds_event_insert(int efd, struct uds_event *event); -+#ifdef QTFS_SERVER -+int uds_proxy_main(int argc, char *argv[]); -+#endif -+#endif -diff --git a/qtfs/ipc/uds_module.h b/qtfs/ipc/uds_module.h -new file mode 100644 -index 0000000..9ccbb9d ---- /dev/null -+++ b/qtfs/ipc/uds_module.h -@@ -0,0 +1,19 @@ -+#ifndef __QTFS_UDS_MODULE_H__ -+#define __QTFS_UDS_MODULE_H__ -+ -+#define UDS_BUILD_CONN_ADDR "/var/run/qtfs/remote_uds.sock" -+#define UDS_DIAG_ADDR "/var/run/qtfs/uds_proxy_diag.sock" -+#define UDS_LOGLEVEL_UPD "/var/run/qtfs/uds_loglevel.sock" -+#define UDS_BUILD_CONN_DIR "/var/run/qtfs/" -+ -+#define UDS_SUN_PATH_LEN 108 // from glibc -+struct uds_proxy_remote_conn_req { -+ unsigned short type; -+ unsigned short resv; -+ char sun_path[UDS_SUN_PATH_LEN]; -+}; -+struct uds_proxy_remote_conn_rsp { -+ int ret; -+}; -+ -+#endif -diff --git a/qtfs/misc.c b/qtfs/misc.c -index 98222bd..44da4e1 100644 ---- a/qtfs/misc.c -+++ b/qtfs/misc.c -@@ -156,6 +156,13 @@ long qtfs_misc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) - } - break; - } -+ case QTFS_IOCTL_UDS_PROXY_PID: -+ if (copy_from_user(&qtfs_uds_proxy_pid, (void *)arg, sizeof(int))) { -+ qtfs_err("ioctl get uds proxy pid failed."); -+ break; -+ } -+ qtfs_info("ioctl get uds proxy process pid is %d", qtfs_uds_proxy_pid); -+ break; - } - return ret; - } -diff --git a/qtfs/qtfs/sb.c b/qtfs/qtfs/sb.c -index 7445fad..104d137 100644 ---- a/qtfs/qtfs/sb.c -+++ b/qtfs/qtfs/sb.c -@@ -288,7 +288,7 @@ ssize_t qtfs_readiter(struct kiocb *kio, struct iov_iter *iov) - - req->fd = private->fd; - if (req->fd <= 0) { -- qtfs_err("qtfs_readiter: invalid file(0x%llx)", req->fd); -+ qtfs_err("qtfs_readiter: invalid file(%d)", req->fd); - qtfs_conn_put_param(pvar); - return -EINVAL; - } -@@ -360,7 +360,7 @@ ssize_t qtfs_writeiter(struct kiocb *kio, struct iov_iter *iov) - - req->d.fd = private->fd; - if (req->d.fd < 0) { -- qtfs_err("qtfs_write: invalid file(0x%llx)", req->d.fd); -+ qtfs_err("qtfs_write: invalid file(%d)", req->d.fd); - qtfs_conn_put_param(pvar); - return -EINVAL; - } -@@ -1172,7 +1172,7 @@ int qtfs_getattr(const struct path *path, struct kstat *stat, u32 req_mask, unsi - *stat = rsp->stat; - qtfs_debug("qtfs getattr success:<%s> blksiz:%u size:%lld mode:%o ino:%llu pathino:%lu. %s\n", req->path, rsp->stat.blksize, - rsp->stat.size, rsp->stat.mode, rsp->stat.ino, inode->i_ino, rsp->stat.ino != inode->i_ino ? "delete current inode" : ""); -- if (inode->i_ino != rsp->stat.ino || rsp->stat.mode != inode->i_mode) { -+ if (inode->i_ino != rsp->stat.ino || inode->i_mode != rsp->stat.mode) { - if (inode->i_nlink > 0){ - drop_nlink(inode); - } -diff --git a/qtfs/qtfs_server/Makefile b/qtfs/qtfs_server/Makefile -index 9c6bcd5..2ff826f 100644 ---- a/qtfs/qtfs_server/Makefile -+++ b/qtfs/qtfs_server/Makefile -@@ -4,15 +4,26 @@ KBUILD=/lib/modules/$(shell uname -r)/build/ - obj-m:=qtfs_server.o - qtfs_server-objs:=../conn.o fsops.o qtfs-server.o ../misc.o - -+DEPGLIB=-lglib-2.0 -I../ -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -+ - all: qtfs_server engine - - qtfs_server: - make -C $(KBUILD) M=$(PWD) modules - --engine: -- gcc -O2 -o engine user_engine.c -lpthread -lglib-2.0 -I../ -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -DQTFS_SERVER -+engine: uds_event.o uds_main.o user_engine.o -+ gcc -O2 -o engine $^ -lpthread $(DEPGLIB) -I../ -I../ipc/ -DQTFS_SERVER -+ -+user_engine.o: -+ cc -g -c -o user_engine.o user_engine.c $(DEPGLIB) -I../ -DQTFS_SERVER -+ -+uds_event.o: -+ cc -g -c -o uds_event.o ../ipc/uds_event.c -DQTFS_SERVER -+ -+uds_main.o: -+ cc -g -c -o uds_main.o ../ipc/uds_main.c -DQTFS_SERVER - - clean: - make -C $(KBUILD) M=$(PWD) clean - rm -rf engine -- rm -rf ../*.o ../.*.o.cmd -+ rm -rf ../*.o -diff --git a/qtfs/qtfs_server/fsops.c b/qtfs/qtfs_server/fsops.c -index 61e8895..6c3e201 100644 ---- a/qtfs/qtfs_server/fsops.c -+++ b/qtfs/qtfs_server/fsops.c -@@ -25,10 +25,11 @@ - - bool in_white_list(char *path, int type) - { -+ int i, in_wl = -1; -+ - if (!whitelist[type]) { - return true; - } -- int i, in_wl = -1; - for (i = 0; i < whitelist[type]->len; i++) { - if (!strncmp(path, whitelist[type]->wl[i].path, whitelist[type]->wl[i].len)){ - in_wl = i; -@@ -202,7 +203,7 @@ static int handle_statfs(struct qtserver_arg *arg) - static int handle_mount(struct qtserver_arg *arg) - { - struct path path; -- int ret, i, in_wl = -1; -+ int ret; - struct qtreq_mount *req = (struct qtreq_mount *)REQ(arg); - struct qtrsp_mount *rsp = (struct qtrsp_mount *)RSP(arg); - if (!in_white_list(req->path, QTFS_WHITELIST_MOUNT)) { -diff --git a/qtfs/qtfs_server/qtfs-server.c b/qtfs/qtfs_server/qtfs-server.c -index b0b8ab0..cbe07f0 100644 ---- a/qtfs/qtfs_server/qtfs-server.c -+++ b/qtfs/qtfs_server/qtfs-server.c -@@ -214,11 +214,6 @@ long qtfs_server_misc_ioctl(struct file *file, unsigned int cmd, unsigned long a - qtfs_server_thread_run = arg; - break; - -- case QTFS_IOCTL_ALLINFO: -- case QTFS_IOCTL_CLEARALL: -- case QTFS_IOCTL_LOGLEVEL: -- ret = qtfs_misc_ioctl(file, cmd, arg); -- break; - case QTFS_IOCTL_WHITELIST: - if (copy_from_user(&len, (void __user *)arg, sizeof(int))) { - qtfs_err("qtfs ioctl white init copy from user failed."); -@@ -239,6 +234,12 @@ long qtfs_server_misc_ioctl(struct file *file, unsigned int cmd, unsigned long a - qtfs_err("init %d list:%d %s", tmp->type, i, whitelist[tmp->type]->wl[i].path); - } - break; -+ case QTFS_IOCTL_ALLINFO: -+ case QTFS_IOCTL_CLEARALL: -+ case QTFS_IOCTL_LOGLEVEL: -+ case QTFS_IOCTL_UDS_PROXY_PID: -+ ret = qtfs_misc_ioctl(file, cmd, arg); -+ break; - default: - qtfs_err("qtfs misc ioctl unknown cmd:%u.", cmd); - break; -diff --git a/qtfs/qtfs_server/user_engine.c b/qtfs/qtfs_server/user_engine.c -index 547935c..a3d627d 100644 ---- a/qtfs/qtfs_server/user_engine.c -+++ b/qtfs/qtfs_server/user_engine.c -@@ -14,6 +14,7 @@ - #include - - #include "comm.h" -+#include "ipc/uds_main.h" - - char wl_type_str[QTFS_WHITELIST_MAX][10] = {"Open", "Write", "Read", "Readdir", "Mkdir", "Rmdir", "Create", "Unlink", "Rename", "Setattr", "Setxattr", "Mount"}; - -@@ -220,13 +221,12 @@ int qtfs_whitelist_init(int fd) - - int main(int argc, char *argv[]) - { -- if (argc != 3) { -- engine_out("Usage: %s .", argv[0]); -- engine_out(" Example: %s 4096 16.", argv[0]); -+ if (argc != 7) { -+ engine_out("Usage: %s .", argv[0]); -+ engine_out(" Example: %s 16 1 192.168.10.10 12121 192.168.10.11 12121.", argv[0]); - return -1; - } -- int psize = atoi(argv[1]); -- int thread_nums = atoi(argv[2]); -+ int thread_nums = atoi(argv[1]); - int fd = open(QTFS_SERVER_FILE, O_RDONLY); - if (fd < 0) { - engine_err("qtfs server file:%s open failed, fd:%d.", QTFS_SERVER_FILE, fd); -@@ -247,9 +247,9 @@ int main(int argc, char *argv[]) - - pthread_t texec[QTFS_MAX_THREADS]; - pthread_t tepoll; -- if (psize > QTFS_USERP_MAXSIZE || thread_nums > QTFS_MAX_THREADS) { -- engine_err("qtfs engine param invalid, size:%d(must <= %d) thread_nums:%d(must <= %d).", -- psize, QTFS_USERP_MAXSIZE, thread_nums, QTFS_MAX_THREADS); -+ if (thread_nums > QTFS_MAX_THREADS) { -+ engine_err("qtfs engine param invalid, thread_nums:%d(must <= %d).", -+ thread_nums, QTFS_MAX_THREADS); - goto end; - } - (void)ioctl(fd, QTFS_IOCTL_EXIT, 1); -@@ -257,24 +257,30 @@ int main(int argc, char *argv[]) - signal(SIGKILL, qtfs_signal_int); - signal(SIGTERM, qtfs_signal_int); - -- struct qtfs_server_userp_s *userp = qtfs_engine_thread_init(fd, thread_nums, psize); -+ struct qtfs_server_userp_s *userp = qtfs_engine_thread_init(fd, thread_nums, QTFS_USERP_SIZE); - if (userp == NULL) { - engine_out("qtfs engine userp init failed."); - goto end; - } - struct engine_arg arg[QTFS_MAX_THREADS]; - for (int i = 0; i < thread_nums; i++) { -- arg[i].psize = psize; -+ arg[i].psize = QTFS_USERP_SIZE; - arg[i].fd = fd; - arg[i].thread_idx = i; - (void)pthread_create(&texec[i], NULL, qtfs_engine_kthread, &arg[i]); - } - (void)pthread_create(&tepoll, NULL, qtfs_engine_epoll_thread, &arg[0]); -+ // 必须放在这个位置,uds main里面最终也有join -+ if (uds_proxy_main(6, &argv[1]) != 0) { -+ engine_out("uds proxy start failed."); -+ goto engine_free; -+ } - for (int i = 0; i < thread_nums; i++) { - pthread_join(texec[i], NULL); - engine_out("qtfs engine join thread %d.", i); - } - pthread_join(tepoll, NULL); -+engine_free: - qtfs_engine_userp_free(userp, thread_nums); - engine_out("qtfs engine join epoll thread."); - end: -diff --git a/qtfs/qtinfo/qtinfo.c b/qtfs/qtinfo/qtinfo.c -index dc88da0..a8ba2e0 100644 ---- a/qtfs/qtinfo/qtinfo.c -+++ b/qtfs/qtinfo/qtinfo.c -@@ -4,9 +4,13 @@ - #include - #include - #include -+#include -+#include -+#include - - #include "qtinfo.h" - #include "comm.h" -+#include "ipc/uds_main.h" - - #ifdef client - #define QTFS_DEV_NAME "/dev/qtfs_client" -@@ -312,6 +316,69 @@ void qtinfo_opt_p(int fd, char *support) - return; - } - -+#define PATH_MAX 4096 -+void qtinfo_opt_u() -+{ -+ int len; -+ struct sockaddr_un svr; -+ int sockfd = socket(AF_UNIX, SOCK_STREAM, 0); -+ if (sockfd < 0) { -+ qtinfo_err("Create socket fd failed."); -+ return; -+ } -+ -+ memset(&svr, 0, sizeof(svr)); -+ svr.sun_family = AF_UNIX; -+ strcpy(svr.sun_path, UDS_DIAG_ADDR); -+ len = offsetof(struct sockaddr_un, sun_path) + strlen(svr.sun_path); -+ if (connect(sockfd, (struct sockaddr *)&svr, len) < 0) { -+ qtinfo_err("connect to %s failed.", UDS_DIAG_ADDR); -+ return; -+ } -+ while (1) { -+ char buf[256]; -+ int n; -+ memset(buf, 0, 256); -+ n = recv(sockfd, buf, 256, 0); -+ if (n <= 0) -+ break; -+ qtinfo_out2("%s", buf); -+ } -+ close(sockfd); -+ return; -+} -+ -+void qtinfo_opt_s() -+{ -+ int len; -+ struct sockaddr_un svr; -+ int sockfd = socket(AF_UNIX, SOCK_STREAM, 0); -+ if (sockfd < 0) { -+ qtinfo_err("Create socket fd failed."); -+ return; -+ } -+ -+ memset(&svr, 0, sizeof(svr)); -+ svr.sun_family = AF_UNIX; -+ strcpy(svr.sun_path, UDS_LOGLEVEL_UPD); -+ len = offsetof(struct sockaddr_un, sun_path) + strlen(svr.sun_path); -+ if (connect(sockfd, (struct sockaddr *)&svr, len) < 0) { -+ qtinfo_err("connect to %s failed.", UDS_LOGLEVEL_UPD); -+ return; -+ } -+ while (1) { -+ char buf[256]; -+ int n; -+ memset(buf, 0, 256); -+ n = recv(sockfd, buf, 256, 0); -+ if (n <= 0) -+ break; -+ qtinfo_out2("%s", buf); -+ } -+ close(sockfd); -+ return; -+ -+} - - static void qtinfo_help(char *exec) - { -@@ -322,6 +389,8 @@ static void qtinfo_help(char *exec) - qtinfo_out(" -l, Set log level(valid param: \"NONE\", \"ERROR\", \"WARN\", \"INFO\", \"DEBUG\")."); - qtinfo_out(" -t, For test informations."); - qtinfo_out(" -p, Epoll support file mode(1: any files; 0: only fifo)."); -+ qtinfo_out(" -u, Display unix socket proxy diagnostic info"); -+ qtinfo_out(" -s, Set unix socket proxy log level(Increase by 1 each time)"); - } - - int main(int argc, char *argv[]) -@@ -334,7 +403,7 @@ int main(int argc, char *argv[]) - qtinfo_err("open file %s failed.", QTFS_DEV_NAME); - return 0; - } -- while ((ch = getopt(argc, argv, "acl:tp:")) != -1) { -+ while ((ch = getopt(argc, argv, "acl:tp:us")) != -1) { - switch (ch) { - case 'a': - qtinfo_opt_a(fd); -@@ -351,6 +420,12 @@ int main(int argc, char *argv[]) - case 'p': - qtinfo_opt_p(fd, optarg); - break; -+ case 'u': -+ qtinfo_opt_u(); -+ break; -+ case 's': -+ qtinfo_opt_s(); -+ break; - default: - qtinfo_help(argv[0]); - break; -diff --git a/qtfs/qtsock.c b/qtfs/qtsock.c -new file mode 100644 -index 0000000..58b2eab ---- /dev/null -+++ b/qtfs/qtsock.c -@@ -0,0 +1,332 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "conn.h" -+#include "log.h" -+#include "comm.h" -+#include "qtfs/syscall.h" -+ -+#define MAX_SOCK_PATH_LEN 108 -+ -+static struct socket *qtfs_sock = NULL; -+static struct mutex qtfs_sock_mutex; -+static char qtfs_sock_path[] = "/var/run/qtfs/remote_uds.sock"; -+ -+struct qtsock_wl_stru qtsock_wl; -+ -+static struct sock *(*origin_unix_find_other)(struct net *net, -+ struct sockaddr_un *sunname, int len, -+ int type, unsigned int hash, int *error); -+ -+struct ftrace_hook { -+ const char *name; -+ void *func; -+ void *origin; -+ -+ unsigned long addr; -+ struct ftrace_ops ops; -+}; -+ -+struct ftrace_hook unix_find_other_hook; -+ -+static int resolve_hook_address(struct ftrace_hook *hook) -+{ -+ hook->addr = qtfs_kallsyms_lookup_name(hook->name); -+ if (!hook->addr) { -+ qtfs_warn("unresolved symbol during resolving hook address:%s\n", hook->name); -+ return -ENOENT; -+ } -+ *((unsigned long *)hook->origin) = hook->addr; -+ -+ return 0; -+} -+ -+static void notrace ftrace_thunk(unsigned long ip, unsigned long parent_ip, -+ struct ftrace_ops *ops, struct pt_regs *regs) -+{ -+ struct ftrace_hook *hook = container_of(ops, struct ftrace_hook, ops); -+ -+ if (!within_module(parent_ip, THIS_MODULE)) -+ regs->ip = (unsigned long)hook->func; -+} -+ -+int install_hook(struct ftrace_hook *hook) -+{ -+ int err; -+ -+ err = resolve_hook_address(hook); -+ if (err) -+ return err; -+ -+ hook->ops.func = ftrace_thunk; -+ hook->ops.flags = FTRACE_OPS_FL_SAVE_REGS | FTRACE_OPS_FL_IPMODIFY; -+ -+ err = ftrace_set_filter_ip(&hook->ops, hook->addr, 0, 0); -+ if (err) { -+ qtfs_err("ftrace_set_filter_ip failed:%d\n", err); -+ return err; -+ } -+ -+ err = register_ftrace_function(&hook->ops); -+ if (err) { -+ qtfs_err("register_ftrace_function failed with :%d\n", err); -+ ftrace_set_filter_ip(&hook->ops, hook->addr, 1, 0); -+ return err; -+ } -+ qtfs_info("install hook(%s) done\n", hook->name); -+ -+ return 0; -+} -+ -+void remove_hook(struct ftrace_hook *hook) -+{ -+ int err; -+ -+ err = unregister_ftrace_function(&hook->ops); -+ if (err) -+ qtfs_err("unregister_ftrace_function failed:%d\n", err); -+ -+ err = ftrace_set_filter_ip(&hook->ops, hook->addr, 1, 0); -+ if (err) -+ qtfs_err("ftrace_set_filter_ip failed:%d\n", err); -+ qtfs_info("remove hook(%s) done", hook->name); -+} -+ -+struct qtfs_sock_req { -+ int magic; -+ int type; -+ char sunname[MAX_SOCK_PATH_LEN]; -+}; -+ -+struct qtfs_sock_rsp { -+ int found; -+}; -+ -+static int qtsock_conn(void) -+{ -+ int ret; -+ struct sockaddr_un saddr; -+ -+ ret = mutex_lock_interruptible(&qtfs_sock_mutex); -+ if (ret <0) { -+ qtfs_err("Failed to get qtfs sock mutex lock:%d\n", ret); -+ return false; -+ } -+ // calling this function means qtfs_sock isn't working properly. -+ // so it's ok to release and clean old qtfs_sock -+ if (qtfs_sock) { -+ sock_release(qtfs_sock); -+ qtfs_sock = NULL; -+ } -+ // connect to userspace unix socket server -+ ret = __sock_create(&init_net, AF_UNIX, SOCK_STREAM, 0, &qtfs_sock, 1); -+ if (ret) { -+ qtfs_err("qtfs sock client init create sock failed:%d\n", ret); -+ mutex_unlock(&qtfs_sock_mutex); -+ return ret; -+ } -+ saddr.sun_family = PF_UNIX; -+ strcpy(saddr.sun_path, qtfs_sock_path); -+ ret = qtfs_sock->ops->connect(qtfs_sock, (struct sockaddr *)&saddr, -+ sizeof(struct sockaddr_un) - 1, 0); -+ if (ret) { -+ qtfs_err("qtfs sock client sock connect failed:%d\n", ret); -+ sock_release(qtfs_sock); -+ qtfs_sock = NULL; -+ mutex_unlock(&qtfs_sock_mutex); -+ return ret; -+ } -+ -+ mutex_unlock(&qtfs_sock_mutex); -+ return ret; -+} -+ -+bool qtfs_udsfind(char *sunname, int len, int type) -+{ -+ struct qtfs_sock_req qs_req; -+ struct qtfs_sock_rsp qs_rsp; -+ struct kvec send_vec, recv_vec; -+ struct msghdr send_msg, recv_msg; -+ int ret; -+ int retry = 0, penalty = 100, i = 0; -+ -+ // qtfs_sock still not initialized, try to connect to server -+ if (!qtfs_sock && (qtsock_conn() < 0)) { -+ qtfs_err("failed to connect to qtfs socket\n"); -+ return false; -+ } -+ if (len > MAX_SOCK_PATH_LEN) { -+ qtfs_err("Invalid socket path name len(%d)\n", len); -+ return false; -+ } -+ memset(&qs_req, 0, sizeof(qs_req)); -+ memset(&qs_rsp, 0, sizeof(qs_rsp)); -+ strncpy(qs_req.sunname, sunname, len); -+ qs_req.type = type; -+ qs_req.magic = 0xDEADBEEF; -+ -+ memset(&send_msg, 0, sizeof(send_msg)); -+ memset(&send_vec, 0, sizeof(send_vec)); -+ memset(&recv_msg, 0, sizeof(recv_msg)); -+ memset(&recv_vec, 0, sizeof(recv_vec)); -+ -+ send_vec.iov_base = &qs_req; -+ send_vec.iov_len = sizeof(qs_req); -+ qtfs_info("qtfs uds find socket(%s), type(%d)\n", sunname, type); -+ -+reconn: -+ if (retry) { -+ for (i = 0; i < retry; i++) { -+ if (qtsock_conn() == 0) -+ break; -+ qtfs_err("qtfs socket reconnect failed for %d trial", i+1); -+ penalty *= 2; -+ msleep(penalty); -+ } -+ } -+ ret = mutex_lock_interruptible(&qtfs_sock_mutex); -+ if (ret < 0) { -+ qtfs_err("Failed to get qtfs sock mutex lock:%d\n", ret); -+ return false; -+ } -+ if (!qtfs_sock) { -+ qtfs_err("qtfs_sock is NULL, please check\n"); -+ mutex_unlock(&qtfs_sock_mutex); -+ return false; -+ } -+ send_msg.msg_flags |= MSG_NOSIGNAL; -+ ret = kernel_sendmsg(qtfs_sock, &send_msg, &send_vec, 1, sizeof(qs_req)); -+ if (ret == -EPIPE && retry == 0) { -+ qtfs_err("uds find connection has broken, try to reconnect\n"); -+ retry = 3; -+ mutex_unlock(&qtfs_sock_mutex); -+ goto reconn; -+ } else if (ret < 0) { -+ qtfs_err("Failed to send uds find message:%d\n", ret); -+ mutex_unlock(&qtfs_sock_mutex); -+ return false; -+ } -+ -+ // waiting for response -+ recv_vec.iov_base = &qs_rsp; -+ recv_vec.iov_len = sizeof(qs_rsp); -+retry: -+ recv_msg.msg_flags |= MSG_NOSIGNAL; -+ ret = kernel_recvmsg(qtfs_sock, &recv_msg, &recv_vec, 1, sizeof(qs_rsp), 0); -+ if (ret == -ERESTARTSYS || ret == -EINTR) { -+ qtfs_err("uds remote find get interrupted, just retry"); -+ msleep(1); -+ goto retry; -+ } -+ mutex_unlock(&qtfs_sock_mutex); -+ if (ret < 0) { -+ qtfs_err("Failed to receive uds find response:%d\n", ret); -+ return false; -+ } -+ qtfs_info("uds remote find socket(%s), type(%d), result:%s\n", sunname, type, qs_rsp.found ? "found" : "not found"); -+ return qs_rsp.found; -+} -+ -+static int uds_find_whitelist(const char *path) -+{ -+ int i; -+ int ret = 1; -+ read_lock(&qtsock_wl.rwlock); -+ for (i = 0; i< qtsock_wl.nums; i++) { -+ if (strncmp(path, qtsock_wl.wl[i], strlen(qtsock_wl.wl[i])) == 0) { -+ ret = 0; -+ break; -+ } -+ } -+ read_unlock(&qtsock_wl.rwlock); -+ return ret; -+} -+ -+static inline bool uds_is_proxy(void) -+{ -+ return (current->tgid == qtfs_uds_proxy_pid); -+} -+ -+static struct sock *qtfs_unix_find_other(struct net *net, -+ struct sockaddr_un *sunname, int len, -+ int type, unsigned int hash, int *error) -+{ -+ struct sock *other = NULL; -+ bool found = false; -+ -+ qtfs_debug("in qtfs_unix_find_other (%s)\n", sunname->sun_path); -+ other = origin_unix_find_other(net, sunname, len, type, hash, error); -+ if (other) { -+ qtfs_debug("find unix other sock(%s) locally", sunname->sun_path); -+ return other; -+ } -+ -+ // do not call remote find if sunname is annomous or sunpath not in whitelist -+ if (!sunname->sun_path[0] || uds_find_whitelist(sunname->sun_path) || -+ uds_is_proxy() == true) { -+ *error = -ECONNREFUSED; -+ return NULL; -+ } -+ -+ qtfs_info("Failed to find unix other sock(%s) locally, try to find remotely\n", sunname->sun_path); -+ // refer userspace service to get remote socket status -+ // if found, which means userspace service has create this unix socket server, just go to origin_unix_find_other, it will be found -+ // if not found, return NULL -+ found = qtfs_udsfind(sunname->sun_path, len, type); -+ if (!found) { -+ qtfs_info("failed to find unix other sock(%s) remotely", sunname->sun_path); -+ *error = -ECONNREFUSED; -+ return NULL; -+ } -+ qtfs_info("find unix other sock(%s) remotely\n", sunname->sun_path); -+ -+ // found it remotely, so we will inform userspace engine to create specfic unix socket and connect to qtfs server -+ // and call unix_find_other locally -+ // xxx: will this be called recursively? Hope not -+ return origin_unix_find_other(net, sunname, len, type, hash, error); -+} -+ -+int qtfs_sock_init(void) -+{ -+ qtfs_kallsyms_hack_init(); -+ -+ qtfs_info("in qtfs ftrace hook unix_find_other\n"); -+ unix_find_other_hook.name = "unix_find_other"; -+ unix_find_other_hook.func = qtfs_unix_find_other; -+ unix_find_other_hook.origin = &origin_unix_find_other; -+ -+ install_hook(&unix_find_other_hook); -+ mutex_init(&qtfs_sock_mutex); -+ rwlock_init(&qtsock_wl.rwlock); -+ qtsock_wl.nums = 0; -+ qtsock_wl.wl = (char **)kmalloc(sizeof(char *) * QTSOCK_WL_MAX_NUM, GFP_KERNEL); -+ if (qtsock_wl.wl == NULL) { -+ -+ qtfs_err("failed to kmalloc wl, max num:%d", QTSOCK_WL_MAX_NUM); -+ } -+ -+ return 0; -+} -+ -+void qtfs_sock_exit(void) -+{ -+ int ret; -+ qtfs_info("exit qtfs ftrace, remove unix_find_other_hook\n"); -+ remove_hook(&unix_find_other_hook); -+ -+ ret = mutex_lock_interruptible(&qtfs_sock_mutex); -+ if (ret < 0) -+ qtfs_err("Failed to get qtfs sock mutex lock:%d\n", ret); -+ // close unix socket connected to userspace -+ if (qtfs_sock) { -+ sock_release(qtfs_sock); -+ qtfs_sock = NULL; -+ } -+ mutex_unlock(&qtfs_sock_mutex); -+} --- -2.33.0 - diff --git a/0008-Modify-the-logic-of-rexec-proxy-process-exit-by-mist.patch b/0008-Modify-the-logic-of-rexec-proxy-process-exit-by-mist.patch new file mode 100644 index 0000000000000000000000000000000000000000..ea1e1b54968500552f29aa50d2958af9c7643d3e --- /dev/null +++ b/0008-Modify-the-logic-of-rexec-proxy-process-exit-by-mist.patch @@ -0,0 +1,35 @@ +From 802188d8d9a06a0c963ecee0b7d30b379dfe2814 Mon Sep 17 00:00:00 2001 +From: yangxin <245051644@qq.com> +Date: Thu, 8 Jun 2023 12:22:58 +0000 +Subject: Modify the logic of rexec proxy process exit by mistake + +Signed-off-by: yangxin <245051644@qq.com> +--- + qtfs/rexec/rexec.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/qtfs/rexec/rexec.c b/qtfs/rexec/rexec.c +index 489ebec..5439fac 100644 +--- a/qtfs/rexec/rexec.c ++++ b/qtfs/rexec/rexec.c +@@ -109,7 +109,7 @@ static int rexec_io(struct rexec_client_event *evt) + ret = write(evt->outfd, buf, len); + if (ret <= 0) { + rexec_err("Read from fd:%d len:%d write to fd:%d failed ret:%d", evt->fd, len, evt->outfd, ret); +- return REXEC_EVENT_EXIT; ++ return REXEC_EVENT_DEL; + } + if (ret != len) { + rexec_err("Read from fd:%d len:%d but write to fd:%d ret:%d", evt->fd, len, evt->outfd, ret); +@@ -285,7 +285,7 @@ static int rexec_run(int efd, int connfd, char *argv[]) + for (int i = 0; i < n; i++) { + struct rexec_client_event *evt = (struct rexec_client_event *)evts[i].data.ptr; + int ret = evt->handler(evt); +- if (evts[i].events & EPOLLHUP || ret == REXEC_EVENT_EXIT) { ++ if (ret == REXEC_EVENT_EXIT) { + process_exit = 1; + } + if (ret == REXEC_EVENT_DEL) { +-- +2.33.0 + diff --git a/0009-Add-rexec-shim.patch b/0009-Add-rexec-shim.patch deleted file mode 100644 index 3a04c9d26452463b530f2737d6750cde20e1069b..0000000000000000000000000000000000000000 --- a/0009-Add-rexec-shim.patch +++ /dev/null @@ -1,3954 +0,0 @@ -From 0a219b5916028f8333bf44563fa7cf17e8f07879 Mon Sep 17 00:00:00 2001 -From: yangxin <245051644@qq.com> -Date: Fri, 10 Feb 2023 17:02:59 +0800 -Subject: [PATCH 5/5] Add rexec shim. - -Signed-off-by: yangxin <245051644@qq.com> ---- - qtfs/rexec/Makefile | 21 +- - qtfs/rexec/client.go | 8 +- - qtfs/rexec/common.go | 11 +- - qtfs/rexec/fd.go | 122 ++ - qtfs/rexec/rshim/Makefile | 10 + - qtfs/rexec/rshim/cJSON.c | 3119 +++++++++++++++++++++++++++++++++ - qtfs/rexec/rshim/cJSON.h | 300 ++++ - qtfs/rexec/rshim/rexec_shim.c | 198 +++ - qtfs/rexec/server.go | 11 +- - 9 files changed, 3788 insertions(+), 12 deletions(-) - create mode 100644 qtfs/rexec/fd.go - create mode 100644 qtfs/rexec/rshim/Makefile - create mode 100644 qtfs/rexec/rshim/cJSON.c - create mode 100644 qtfs/rexec/rshim/cJSON.h - create mode 100644 qtfs/rexec/rshim/rexec_shim.c - -diff --git a/qtfs/rexec/Makefile b/qtfs/rexec/Makefile -index 86d4f78..96fbdb0 100644 ---- a/qtfs/rexec/Makefile -+++ b/qtfs/rexec/Makefile -@@ -1,11 +1,22 @@ --all: rexec rexec_server -+all: rexec rexec_server rexec_shim - --rexec : client.go common.go -- go build -o rexec client.go common.go -+rexec : client.go common.go fd.go -+ go build -o rexec client.go common.go fd.go - --rexec_server : server.go common.go -- go build -o rexec_server server.go common.go -+rexec_server : server.go common.go fd.go -+ go build -o rexec_server server.go common.go fd.go - test: - go test -v ./common_test.go ./common.go -+ -+rexec_shim: -+ $(MAKE) -C ./rshim -+ -+install: -+ cp -f rexec /usr/bin/ -+ cp -f rexec /usr/bin/ -+ $(MAKE) install -C ./rshim -+ - clean: - rm -rf rexec rexec_server -+ $(MAKE) clean -C ./rshim -+ -diff --git a/qtfs/rexec/client.go b/qtfs/rexec/client.go -index dc1af8b..55835de 100644 ---- a/qtfs/rexec/client.go -+++ b/qtfs/rexec/client.go -@@ -8,6 +8,7 @@ import ( - "os/signal" - "path/filepath" - "strconv" -+ "strings" - "syscall" - "time" - -@@ -61,6 +62,9 @@ func removePidFile() { - - func cleanRedundantPidFile() { - filepath.Walk(rexecPidDir, func(path string, info os.FileInfo, err error) error { -+ if strings.TrimSuffix(path, "/") == strings.TrimSuffix(rexecPidDir, "/") { -+ return nil -+ } - f, err := os.Open(path) - if err != nil { - // open failed, just skip -@@ -147,7 +151,9 @@ func main() { - Stderr: os.Stderr, - Env: append([]string{}, os.Environ()...), - StatusChan: remoteSender, -+ Files: make(map[int]FileInfo), - } -+ checkpointFileInfo(command.Files) - - err = sender.Send(command) - if err != nil { -@@ -168,7 +174,7 @@ retry: - log.Fatal(err) - } - if (response.WhiteList == 0) { -- log.Fatalf("%s command in White List of rexec server\n", command.Cmd) -+ log.Fatalf("%s command not in White List of rexec server\n", command.Cmd) - } - pid := response.Pid - lpid := os.Getpid() -diff --git a/qtfs/rexec/common.go b/qtfs/rexec/common.go -index b59b12b..a74c32b 100644 ---- a/qtfs/rexec/common.go -+++ b/qtfs/rexec/common.go -@@ -1,16 +1,16 @@ - package main - - import ( -+ "encoding/json" - "fmt" - "io" -+ "io/ioutil" - "net" - "net/url" - "os" - "strconv" - "strings" - "syscall" -- "io/ioutil" -- "encoding/json" - - "github.com/docker/libchan" - ) -@@ -29,6 +29,7 @@ type RemoteCommand struct { - Stderr io.WriteCloser - StatusChan libchan.Sender - Cgroups map[string]string -+ Files map[int]FileInfo - } - - func CheckRight(fileName string) error { -@@ -43,11 +44,11 @@ func CheckRight(fileName string) error { - gid = int(stat.Gid) - mode = int(stat.Mode) - -- if (uid != 0 || gid != 0) { -+ if uid != 0 || gid != 0 { - return fmt.Errorf("Owner of %s must be root\n", fileName) - } - -- if (mode & 0777 != 0400) { -+ if mode & 0777 != 0400 { - return fmt.Errorf("Mode of %s must be 0400\n", fileName) - } - -@@ -113,7 +114,7 @@ func parseUnixAddr(inAddr string) (NetAddr, error) { - }, nil - } - --func readAddrFromFile(role string) (string) { -+func readAddrFromFile(role string) string { - fileName := fmt.Sprintf("%s/%s.json", configDir, role) - if err := CheckRight(fileName); err != nil { - fmt.Printf("Check right of %s failed: %s", fileName, err) -diff --git a/qtfs/rexec/fd.go b/qtfs/rexec/fd.go -new file mode 100644 -index 0000000..acff8d4 ---- /dev/null -+++ b/qtfs/rexec/fd.go -@@ -0,0 +1,122 @@ -+package main -+ -+import ( -+ "encoding/json" -+ "fmt" -+ "io/ioutil" -+ "log" -+ "math/rand" -+ "os" -+ "path/filepath" -+ "sort" -+ "strconv" -+ "strings" -+) -+ -+const FdPath = "/var/run/rexec/fds/" -+ -+type FileInfo struct { -+ Fd int -+ Path string -+ Perm int -+ Offset int -+} -+ -+type Files struct { -+ Files []FileInfo -+} -+ -+var defaultLetters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") -+ -+func randString(n int) string { -+ b := make([]rune, n) -+ letterLen := len(defaultLetters) -+ -+ for i := range b { -+ b[i] = defaultLetters[rand.Intn(letterLen)] -+ } -+ -+ return string(b) -+} -+ -+func getPosAndFlags(path string) (int, int, error) { -+ content, err := ioutil.ReadFile(path) -+ if err != nil { -+ log.Printf("failed to read file(%s):%s", path, err.Error()) -+ return 0, 0, err -+ } -+ var pos, flags int -+ fmt.Sscanf(string(content), "pos:%d\nflags:%o", &pos, &flags) -+ return pos, flags, nil -+} -+ -+func checkpointFileInfo(fdMaps map[int]FileInfo) { -+ procPath := "/proc/self" -+ fdPath := procPath + "/fd/" -+ fdinfoPath := procPath + "/fdinfo/" -+ -+ filepath.Walk(fdPath, func(path string, fi os.FileInfo, err error) error { -+ if fi == nil || err != nil { -+ log.Printf("path %s failed with %s\n", path, err.Error()) -+ return nil -+ } -+ fdstr := strings.TrimPrefix(path, fdPath) -+ if fdstr == "" { -+ return nil -+ } -+ fd, err := strconv.Atoi(fdstr) -+ if err != nil { -+ log.Printf("convert fd string(%s) to int failed: %s\n", fdstr, err.Error()) -+ return nil -+ } -+ -+ linkPath, err := os.Readlink(path) -+ if err != nil { -+ log.Printf("readlink (%s) failed with: %s\n", path, err.Error()) -+ return nil -+ } -+ // skip stdin/stdout/stderr or non-regular files -+ if fd < 3 || !strings.HasPrefix(linkPath, "/") { -+ return nil -+ } -+ -+ pos, flags, err := getPosAndFlags(fdinfoPath + fdstr) -+ if err != nil { -+ return nil -+ } -+ fdMaps[fd] = FileInfo{ -+ Fd: fd, -+ Path: linkPath, -+ Perm: flags, -+ Offset: pos, -+ } -+ return nil -+ }) -+} -+ -+func restoreFileInfo(cmd string, fdMaps map[int]FileInfo) string { -+ var fds []int -+ var fs Files -+ -+ for fd := range fdMaps { -+ fds = append(fds, fd) -+ } -+ -+ sort.Ints(fds) -+ fs.Files = []FileInfo{} -+ for _, fd := range fds { -+ fs.Files = append(fs.Files, fdMaps[fd]) -+ } -+ js, err := json.Marshal(fs) -+ if err != nil { -+ return "" -+ } -+ os.MkdirAll(FdPath, os.ModePerm) -+ _, cmdName := filepath.Split(cmd) -+ fName := FdPath + cmdName + "-" + randString(20) + ".json" -+ if err := ioutil.WriteFile(fName, js, 0640); err != nil { -+ log.Printf("write %s faild with error: %s\n", fName, err.Error()) -+ return "" -+ } -+ return fName -+} -diff --git a/qtfs/rexec/rshim/Makefile b/qtfs/rexec/rshim/Makefile -new file mode 100644 -index 0000000..6e28911 ---- /dev/null -+++ b/qtfs/rexec/rshim/Makefile -@@ -0,0 +1,10 @@ -+all: rexec_shim -+ -+rexec_shim: -+ gcc -g -O2 -o rexec_shim rexec_shim.c cJSON.c -+ -+install: -+ cp rexec_shim /usr/bin/ -+ -+clean: -+ rm -rf rexec_shim *.o -diff --git a/qtfs/rexec/rshim/cJSON.c b/qtfs/rexec/rshim/cJSON.c -new file mode 100644 -index 0000000..524ba46 ---- /dev/null -+++ b/qtfs/rexec/rshim/cJSON.c -@@ -0,0 +1,3119 @@ -+/* -+ Copyright (c) 2009-2017 Dave Gamble and cJSON contributors -+ -+ Permission is hereby granted, free of charge, to any person obtaining a copy -+ of this software and associated documentation files (the "Software"), to deal -+ in the Software without restriction, including without limitation the rights -+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ copies of the Software, and to permit persons to whom the Software is -+ furnished to do so, subject to the following conditions: -+ -+ The above copyright notice and this permission notice shall be included in -+ all copies or substantial portions of the Software. -+ -+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ THE SOFTWARE. -+*/ -+ -+/* cJSON */ -+/* JSON parser in C. */ -+ -+/* disable warnings about old C89 functions in MSVC */ -+#if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) -+#define _CRT_SECURE_NO_DEPRECATE -+#endif -+ -+#ifdef __GNUC__ -+#pragma GCC visibility push(default) -+#endif -+#if defined(_MSC_VER) -+#pragma warning (push) -+/* disable warning about single line comments in system headers */ -+#pragma warning (disable : 4001) -+#endif -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#ifdef ENABLE_LOCALES -+#include -+#endif -+ -+#if defined(_MSC_VER) -+#pragma warning (pop) -+#endif -+#ifdef __GNUC__ -+#pragma GCC visibility pop -+#endif -+ -+#include "cJSON.h" -+ -+/* define our own boolean type */ -+#ifdef true -+#undef true -+#endif -+#define true ((cJSON_bool)1) -+ -+#ifdef false -+#undef false -+#endif -+#define false ((cJSON_bool)0) -+ -+/* define isnan and isinf for ANSI C, if in C99 or above, isnan and isinf has been defined in math.h */ -+#ifndef isinf -+#define isinf(d) (isnan((d - d)) && !isnan(d)) -+#endif -+#ifndef isnan -+#define isnan(d) (d != d) -+#endif -+ -+#ifndef NAN -+#ifdef _WIN32 -+#define NAN sqrt(-1.0) -+#else -+#define NAN 0.0/0.0 -+#endif -+#endif -+ -+typedef struct { -+ const unsigned char *json; -+ size_t position; -+} error; -+static error global_error = { NULL, 0 }; -+ -+CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) -+{ -+ return (const char*) (global_error.json + global_error.position); -+} -+ -+CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item) -+{ -+ if (!cJSON_IsString(item)) -+ { -+ return NULL; -+ } -+ -+ return item->valuestring; -+} -+ -+CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item) -+{ -+ if (!cJSON_IsNumber(item)) -+ { -+ return (double) NAN; -+ } -+ -+ return item->valuedouble; -+} -+ -+/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ -+#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 15) -+ #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. -+#endif -+ -+CJSON_PUBLIC(const char*) cJSON_Version(void) -+{ -+ static char version[15]; -+ sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH); -+ -+ return version; -+} -+ -+/* Case insensitive string comparison, doesn't consider two NULL pointers equal though */ -+static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2) -+{ -+ if ((string1 == NULL) || (string2 == NULL)) -+ { -+ return 1; -+ } -+ -+ if (string1 == string2) -+ { -+ return 0; -+ } -+ -+ for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++) -+ { -+ if (*string1 == '\0') -+ { -+ return 0; -+ } -+ } -+ -+ return tolower(*string1) - tolower(*string2); -+} -+ -+typedef struct internal_hooks -+{ -+ void *(CJSON_CDECL *allocate)(size_t size); -+ void (CJSON_CDECL *deallocate)(void *pointer); -+ void *(CJSON_CDECL *reallocate)(void *pointer, size_t size); -+} internal_hooks; -+ -+#if defined(_MSC_VER) -+/* work around MSVC error C2322: '...' address of dllimport '...' is not static */ -+static void * CJSON_CDECL internal_malloc(size_t size) -+{ -+ return malloc(size); -+} -+static void CJSON_CDECL internal_free(void *pointer) -+{ -+ free(pointer); -+} -+static void * CJSON_CDECL internal_realloc(void *pointer, size_t size) -+{ -+ return realloc(pointer, size); -+} -+#else -+#define internal_malloc malloc -+#define internal_free free -+#define internal_realloc realloc -+#endif -+ -+/* strlen of character literals resolved at compile time */ -+#define static_strlen(string_literal) (sizeof(string_literal) - sizeof("")) -+ -+static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc }; -+ -+static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks) -+{ -+ size_t length = 0; -+ unsigned char *copy = NULL; -+ -+ if (string == NULL) -+ { -+ return NULL; -+ } -+ -+ length = strlen((const char*)string) + sizeof(""); -+ copy = (unsigned char*)hooks->allocate(length); -+ if (copy == NULL) -+ { -+ return NULL; -+ } -+ memcpy(copy, string, length); -+ -+ return copy; -+} -+ -+CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks) -+{ -+ if (hooks == NULL) -+ { -+ /* Reset hooks */ -+ global_hooks.allocate = malloc; -+ global_hooks.deallocate = free; -+ global_hooks.reallocate = realloc; -+ return; -+ } -+ -+ global_hooks.allocate = malloc; -+ if (hooks->malloc_fn != NULL) -+ { -+ global_hooks.allocate = hooks->malloc_fn; -+ } -+ -+ global_hooks.deallocate = free; -+ if (hooks->free_fn != NULL) -+ { -+ global_hooks.deallocate = hooks->free_fn; -+ } -+ -+ /* use realloc only if both free and malloc are used */ -+ global_hooks.reallocate = NULL; -+ if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free)) -+ { -+ global_hooks.reallocate = realloc; -+ } -+} -+ -+/* Internal constructor. */ -+static cJSON *cJSON_New_Item(const internal_hooks * const hooks) -+{ -+ cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON)); -+ if (node) -+ { -+ memset(node, '\0', sizeof(cJSON)); -+ } -+ -+ return node; -+} -+ -+/* Delete a cJSON structure. */ -+CJSON_PUBLIC(void) cJSON_Delete(cJSON *item) -+{ -+ cJSON *next = NULL; -+ while (item != NULL) -+ { -+ next = item->next; -+ if (!(item->type & cJSON_IsReference) && (item->child != NULL)) -+ { -+ cJSON_Delete(item->child); -+ } -+ if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) -+ { -+ global_hooks.deallocate(item->valuestring); -+ } -+ if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) -+ { -+ global_hooks.deallocate(item->string); -+ } -+ global_hooks.deallocate(item); -+ item = next; -+ } -+} -+ -+/* get the decimal point character of the current locale */ -+static unsigned char get_decimal_point(void) -+{ -+#ifdef ENABLE_LOCALES -+ struct lconv *lconv = localeconv(); -+ return (unsigned char) lconv->decimal_point[0]; -+#else -+ return '.'; -+#endif -+} -+ -+typedef struct -+{ -+ const unsigned char *content; -+ size_t length; -+ size_t offset; -+ size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */ -+ internal_hooks hooks; -+} parse_buffer; -+ -+/* check if the given size is left to read in a given parse buffer (starting with 1) */ -+#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length)) -+/* check if the buffer can be accessed at the given index (starting with 0) */ -+#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length)) -+#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index)) -+/* get a pointer to the buffer at the position */ -+#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset) -+ -+/* Parse the input text to generate a number, and populate the result into item. */ -+static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer) -+{ -+ double number = 0; -+ unsigned char *after_end = NULL; -+ unsigned char number_c_string[64]; -+ unsigned char decimal_point = get_decimal_point(); -+ size_t i = 0; -+ -+ if ((input_buffer == NULL) || (input_buffer->content == NULL)) -+ { -+ return false; -+ } -+ -+ /* copy the number into a temporary buffer and replace '.' with the decimal point -+ * of the current locale (for strtod) -+ * This also takes care of '\0' not necessarily being available for marking the end of the input */ -+ for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) -+ { -+ switch (buffer_at_offset(input_buffer)[i]) -+ { -+ case '0': -+ case '1': -+ case '2': -+ case '3': -+ case '4': -+ case '5': -+ case '6': -+ case '7': -+ case '8': -+ case '9': -+ case '+': -+ case '-': -+ case 'e': -+ case 'E': -+ number_c_string[i] = buffer_at_offset(input_buffer)[i]; -+ break; -+ -+ case '.': -+ number_c_string[i] = decimal_point; -+ break; -+ -+ default: -+ goto loop_end; -+ } -+ } -+loop_end: -+ number_c_string[i] = '\0'; -+ -+ number = strtod((const char*)number_c_string, (char**)&after_end); -+ if (number_c_string == after_end) -+ { -+ return false; /* parse_error */ -+ } -+ -+ item->valuedouble = number; -+ -+ /* use saturation in case of overflow */ -+ if (number >= INT_MAX) -+ { -+ item->valueint = INT_MAX; -+ } -+ else if (number <= (double)INT_MIN) -+ { -+ item->valueint = INT_MIN; -+ } -+ else -+ { -+ item->valueint = (int)number; -+ } -+ -+ item->type = cJSON_Number; -+ -+ input_buffer->offset += (size_t)(after_end - number_c_string); -+ return true; -+} -+ -+/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */ -+CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) -+{ -+ if (number >= INT_MAX) -+ { -+ object->valueint = INT_MAX; -+ } -+ else if (number <= (double)INT_MIN) -+ { -+ object->valueint = INT_MIN; -+ } -+ else -+ { -+ object->valueint = (int)number; -+ } -+ -+ return object->valuedouble = number; -+} -+ -+CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring) -+{ -+ char *copy = NULL; -+ /* if object's type is not cJSON_String or is cJSON_IsReference, it should not set valuestring */ -+ if (!(object->type & cJSON_String) || (object->type & cJSON_IsReference)) -+ { -+ return NULL; -+ } -+ if (strlen(valuestring) <= strlen(object->valuestring)) -+ { -+ strcpy(object->valuestring, valuestring); -+ return object->valuestring; -+ } -+ copy = (char*) cJSON_strdup((const unsigned char*)valuestring, &global_hooks); -+ if (copy == NULL) -+ { -+ return NULL; -+ } -+ if (object->valuestring != NULL) -+ { -+ cJSON_free(object->valuestring); -+ } -+ object->valuestring = copy; -+ -+ return copy; -+} -+ -+typedef struct -+{ -+ unsigned char *buffer; -+ size_t length; -+ size_t offset; -+ size_t depth; /* current nesting depth (for formatted printing) */ -+ cJSON_bool noalloc; -+ cJSON_bool format; /* is this print a formatted print */ -+ internal_hooks hooks; -+} printbuffer; -+ -+/* realloc printbuffer if necessary to have at least "needed" bytes more */ -+static unsigned char* ensure(printbuffer * const p, size_t needed) -+{ -+ unsigned char *newbuffer = NULL; -+ size_t newsize = 0; -+ -+ if ((p == NULL) || (p->buffer == NULL)) -+ { -+ return NULL; -+ } -+ -+ if ((p->length > 0) && (p->offset >= p->length)) -+ { -+ /* make sure that offset is valid */ -+ return NULL; -+ } -+ -+ if (needed > INT_MAX) -+ { -+ /* sizes bigger than INT_MAX are currently not supported */ -+ return NULL; -+ } -+ -+ needed += p->offset + 1; -+ if (needed <= p->length) -+ { -+ return p->buffer + p->offset; -+ } -+ -+ if (p->noalloc) { -+ return NULL; -+ } -+ -+ /* calculate new buffer size */ -+ if (needed > (INT_MAX / 2)) -+ { -+ /* overflow of int, use INT_MAX if possible */ -+ if (needed <= INT_MAX) -+ { -+ newsize = INT_MAX; -+ } -+ else -+ { -+ return NULL; -+ } -+ } -+ else -+ { -+ newsize = needed * 2; -+ } -+ -+ if (p->hooks.reallocate != NULL) -+ { -+ /* reallocate with realloc if available */ -+ newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize); -+ if (newbuffer == NULL) -+ { -+ p->hooks.deallocate(p->buffer); -+ p->length = 0; -+ p->buffer = NULL; -+ -+ return NULL; -+ } -+ } -+ else -+ { -+ /* otherwise reallocate manually */ -+ newbuffer = (unsigned char*)p->hooks.allocate(newsize); -+ if (!newbuffer) -+ { -+ p->hooks.deallocate(p->buffer); -+ p->length = 0; -+ p->buffer = NULL; -+ -+ return NULL; -+ } -+ -+ memcpy(newbuffer, p->buffer, p->offset + 1); -+ p->hooks.deallocate(p->buffer); -+ } -+ p->length = newsize; -+ p->buffer = newbuffer; -+ -+ return newbuffer + p->offset; -+} -+ -+/* calculate the new length of the string in a printbuffer and update the offset */ -+static void update_offset(printbuffer * const buffer) -+{ -+ const unsigned char *buffer_pointer = NULL; -+ if ((buffer == NULL) || (buffer->buffer == NULL)) -+ { -+ return; -+ } -+ buffer_pointer = buffer->buffer + buffer->offset; -+ -+ buffer->offset += strlen((const char*)buffer_pointer); -+} -+ -+/* securely comparison of floating-point variables */ -+static cJSON_bool compare_double(double a, double b) -+{ -+ double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b); -+ return (fabs(a - b) <= maxVal * DBL_EPSILON); -+} -+ -+/* Render the number nicely from the given item into a string. */ -+static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer) -+{ -+ unsigned char *output_pointer = NULL; -+ double d = item->valuedouble; -+ int length = 0; -+ size_t i = 0; -+ unsigned char number_buffer[26] = {0}; /* temporary buffer to print the number into */ -+ unsigned char decimal_point = get_decimal_point(); -+ double test = 0.0; -+ -+ if (output_buffer == NULL) -+ { -+ return false; -+ } -+ -+ /* This checks for NaN and Infinity */ -+ if (isnan(d) || isinf(d)) -+ { -+ length = sprintf((char*)number_buffer, "null"); -+ } -+ else if(d == (double)item->valueint) -+ { -+ length = sprintf((char*)number_buffer, "%d", item->valueint); -+ } -+ else -+ { -+ /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ -+ length = sprintf((char*)number_buffer, "%1.15g", d); -+ -+ /* Check whether the original double can be recovered */ -+ if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d)) -+ { -+ /* If not, print with 17 decimal places of precision */ -+ length = sprintf((char*)number_buffer, "%1.17g", d); -+ } -+ } -+ -+ /* sprintf failed or buffer overrun occurred */ -+ if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) -+ { -+ return false; -+ } -+ -+ /* reserve appropriate space in the output */ -+ output_pointer = ensure(output_buffer, (size_t)length + sizeof("")); -+ if (output_pointer == NULL) -+ { -+ return false; -+ } -+ -+ /* copy the printed number to the output and replace locale -+ * dependent decimal point with '.' */ -+ for (i = 0; i < ((size_t)length); i++) -+ { -+ if (number_buffer[i] == decimal_point) -+ { -+ output_pointer[i] = '.'; -+ continue; -+ } -+ -+ output_pointer[i] = number_buffer[i]; -+ } -+ output_pointer[i] = '\0'; -+ -+ output_buffer->offset += (size_t)length; -+ -+ return true; -+} -+ -+/* parse 4 digit hexadecimal number */ -+static unsigned parse_hex4(const unsigned char * const input) -+{ -+ unsigned int h = 0; -+ size_t i = 0; -+ -+ for (i = 0; i < 4; i++) -+ { -+ /* parse digit */ -+ if ((input[i] >= '0') && (input[i] <= '9')) -+ { -+ h += (unsigned int) input[i] - '0'; -+ } -+ else if ((input[i] >= 'A') && (input[i] <= 'F')) -+ { -+ h += (unsigned int) 10 + input[i] - 'A'; -+ } -+ else if ((input[i] >= 'a') && (input[i] <= 'f')) -+ { -+ h += (unsigned int) 10 + input[i] - 'a'; -+ } -+ else /* invalid */ -+ { -+ return 0; -+ } -+ -+ if (i < 3) -+ { -+ /* shift left to make place for the next nibble */ -+ h = h << 4; -+ } -+ } -+ -+ return h; -+} -+ -+/* converts a UTF-16 literal to UTF-8 -+ * A literal can be one or two sequences of the form \uXXXX */ -+static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer) -+{ -+ long unsigned int codepoint = 0; -+ unsigned int first_code = 0; -+ const unsigned char *first_sequence = input_pointer; -+ unsigned char utf8_length = 0; -+ unsigned char utf8_position = 0; -+ unsigned char sequence_length = 0; -+ unsigned char first_byte_mark = 0; -+ -+ if ((input_end - first_sequence) < 6) -+ { -+ /* input ends unexpectedly */ -+ goto fail; -+ } -+ -+ /* get the first utf16 sequence */ -+ first_code = parse_hex4(first_sequence + 2); -+ -+ /* check that the code is valid */ -+ if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) -+ { -+ goto fail; -+ } -+ -+ /* UTF16 surrogate pair */ -+ if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) -+ { -+ const unsigned char *second_sequence = first_sequence + 6; -+ unsigned int second_code = 0; -+ sequence_length = 12; /* \uXXXX\uXXXX */ -+ -+ if ((input_end - second_sequence) < 6) -+ { -+ /* input ends unexpectedly */ -+ goto fail; -+ } -+ -+ if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) -+ { -+ /* missing second half of the surrogate pair */ -+ goto fail; -+ } -+ -+ /* get the second utf16 sequence */ -+ second_code = parse_hex4(second_sequence + 2); -+ /* check that the code is valid */ -+ if ((second_code < 0xDC00) || (second_code > 0xDFFF)) -+ { -+ /* invalid second half of the surrogate pair */ -+ goto fail; -+ } -+ -+ -+ /* calculate the unicode codepoint from the surrogate pair */ -+ codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF)); -+ } -+ else -+ { -+ sequence_length = 6; /* \uXXXX */ -+ codepoint = first_code; -+ } -+ -+ /* encode as UTF-8 -+ * takes at maximum 4 bytes to encode: -+ * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ -+ if (codepoint < 0x80) -+ { -+ /* normal ascii, encoding 0xxxxxxx */ -+ utf8_length = 1; -+ } -+ else if (codepoint < 0x800) -+ { -+ /* two bytes, encoding 110xxxxx 10xxxxxx */ -+ utf8_length = 2; -+ first_byte_mark = 0xC0; /* 11000000 */ -+ } -+ else if (codepoint < 0x10000) -+ { -+ /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */ -+ utf8_length = 3; -+ first_byte_mark = 0xE0; /* 11100000 */ -+ } -+ else if (codepoint <= 0x10FFFF) -+ { -+ /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */ -+ utf8_length = 4; -+ first_byte_mark = 0xF0; /* 11110000 */ -+ } -+ else -+ { -+ /* invalid unicode codepoint */ -+ goto fail; -+ } -+ -+ /* encode as utf8 */ -+ for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) -+ { -+ /* 10xxxxxx */ -+ (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF); -+ codepoint >>= 6; -+ } -+ /* encode first byte */ -+ if (utf8_length > 1) -+ { -+ (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF); -+ } -+ else -+ { -+ (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F); -+ } -+ -+ *output_pointer += utf8_length; -+ -+ return sequence_length; -+ -+fail: -+ return 0; -+} -+ -+/* Parse the input text into an unescaped cinput, and populate item. */ -+static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer) -+{ -+ const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1; -+ const unsigned char *input_end = buffer_at_offset(input_buffer) + 1; -+ unsigned char *output_pointer = NULL; -+ unsigned char *output = NULL; -+ -+ /* not a string */ -+ if (buffer_at_offset(input_buffer)[0] != '\"') -+ { -+ goto fail; -+ } -+ -+ { -+ /* calculate approximate size of the output (overestimate) */ -+ size_t allocation_length = 0; -+ size_t skipped_bytes = 0; -+ while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) -+ { -+ /* is escape sequence */ -+ if (input_end[0] == '\\') -+ { -+ if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length) -+ { -+ /* prevent buffer overflow when last input character is a backslash */ -+ goto fail; -+ } -+ skipped_bytes++; -+ input_end++; -+ } -+ input_end++; -+ } -+ if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) -+ { -+ goto fail; /* string ended unexpectedly */ -+ } -+ -+ /* This is at most how much we need for the output */ -+ allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes; -+ output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof("")); -+ if (output == NULL) -+ { -+ goto fail; /* allocation failure */ -+ } -+ } -+ -+ output_pointer = output; -+ /* loop through the string literal */ -+ while (input_pointer < input_end) -+ { -+ if (*input_pointer != '\\') -+ { -+ *output_pointer++ = *input_pointer++; -+ } -+ /* escape sequence */ -+ else -+ { -+ unsigned char sequence_length = 2; -+ if ((input_end - input_pointer) < 1) -+ { -+ goto fail; -+ } -+ -+ switch (input_pointer[1]) -+ { -+ case 'b': -+ *output_pointer++ = '\b'; -+ break; -+ case 'f': -+ *output_pointer++ = '\f'; -+ break; -+ case 'n': -+ *output_pointer++ = '\n'; -+ break; -+ case 'r': -+ *output_pointer++ = '\r'; -+ break; -+ case 't': -+ *output_pointer++ = '\t'; -+ break; -+ case '\"': -+ case '\\': -+ case '/': -+ *output_pointer++ = input_pointer[1]; -+ break; -+ -+ /* UTF-16 literal */ -+ case 'u': -+ sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer); -+ if (sequence_length == 0) -+ { -+ /* failed to convert UTF16-literal to UTF-8 */ -+ goto fail; -+ } -+ break; -+ -+ default: -+ goto fail; -+ } -+ input_pointer += sequence_length; -+ } -+ } -+ -+ /* zero terminate the output */ -+ *output_pointer = '\0'; -+ -+ item->type = cJSON_String; -+ item->valuestring = (char*)output; -+ -+ input_buffer->offset = (size_t) (input_end - input_buffer->content); -+ input_buffer->offset++; -+ -+ return true; -+ -+fail: -+ if (output != NULL) -+ { -+ input_buffer->hooks.deallocate(output); -+ } -+ -+ if (input_pointer != NULL) -+ { -+ input_buffer->offset = (size_t)(input_pointer - input_buffer->content); -+ } -+ -+ return false; -+} -+ -+/* Render the cstring provided to an escaped version that can be printed. */ -+static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer) -+{ -+ const unsigned char *input_pointer = NULL; -+ unsigned char *output = NULL; -+ unsigned char *output_pointer = NULL; -+ size_t output_length = 0; -+ /* numbers of additional characters needed for escaping */ -+ size_t escape_characters = 0; -+ -+ if (output_buffer == NULL) -+ { -+ return false; -+ } -+ -+ /* empty string */ -+ if (input == NULL) -+ { -+ output = ensure(output_buffer, sizeof("\"\"")); -+ if (output == NULL) -+ { -+ return false; -+ } -+ strcpy((char*)output, "\"\""); -+ -+ return true; -+ } -+ -+ /* set "flag" to 1 if something needs to be escaped */ -+ for (input_pointer = input; *input_pointer; input_pointer++) -+ { -+ switch (*input_pointer) -+ { -+ case '\"': -+ case '\\': -+ case '\b': -+ case '\f': -+ case '\n': -+ case '\r': -+ case '\t': -+ /* one character escape sequence */ -+ escape_characters++; -+ break; -+ default: -+ if (*input_pointer < 32) -+ { -+ /* UTF-16 escape sequence uXXXX */ -+ escape_characters += 5; -+ } -+ break; -+ } -+ } -+ output_length = (size_t)(input_pointer - input) + escape_characters; -+ -+ output = ensure(output_buffer, output_length + sizeof("\"\"")); -+ if (output == NULL) -+ { -+ return false; -+ } -+ -+ /* no characters have to be escaped */ -+ if (escape_characters == 0) -+ { -+ output[0] = '\"'; -+ memcpy(output + 1, input, output_length); -+ output[output_length + 1] = '\"'; -+ output[output_length + 2] = '\0'; -+ -+ return true; -+ } -+ -+ output[0] = '\"'; -+ output_pointer = output + 1; -+ /* copy the string */ -+ for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) -+ { -+ if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) -+ { -+ /* normal character, copy */ -+ *output_pointer = *input_pointer; -+ } -+ else -+ { -+ /* character needs to be escaped */ -+ *output_pointer++ = '\\'; -+ switch (*input_pointer) -+ { -+ case '\\': -+ *output_pointer = '\\'; -+ break; -+ case '\"': -+ *output_pointer = '\"'; -+ break; -+ case '\b': -+ *output_pointer = 'b'; -+ break; -+ case '\f': -+ *output_pointer = 'f'; -+ break; -+ case '\n': -+ *output_pointer = 'n'; -+ break; -+ case '\r': -+ *output_pointer = 'r'; -+ break; -+ case '\t': -+ *output_pointer = 't'; -+ break; -+ default: -+ /* escape and print as unicode codepoint */ -+ sprintf((char*)output_pointer, "u%04x", *input_pointer); -+ output_pointer += 4; -+ break; -+ } -+ } -+ } -+ output[output_length + 1] = '\"'; -+ output[output_length + 2] = '\0'; -+ -+ return true; -+} -+ -+/* Invoke print_string_ptr (which is useful) on an item. */ -+static cJSON_bool print_string(const cJSON * const item, printbuffer * const p) -+{ -+ return print_string_ptr((unsigned char*)item->valuestring, p); -+} -+ -+/* Predeclare these prototypes. */ -+static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer); -+static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer); -+static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer); -+static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer); -+static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer); -+static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer); -+ -+/* Utility to jump whitespace and cr/lf */ -+static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer) -+{ -+ if ((buffer == NULL) || (buffer->content == NULL)) -+ { -+ return NULL; -+ } -+ -+ if (cannot_access_at_index(buffer, 0)) -+ { -+ return buffer; -+ } -+ -+ while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) -+ { -+ buffer->offset++; -+ } -+ -+ if (buffer->offset == buffer->length) -+ { -+ buffer->offset--; -+ } -+ -+ return buffer; -+} -+ -+/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */ -+static parse_buffer *skip_utf8_bom(parse_buffer * const buffer) -+{ -+ if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0)) -+ { -+ return NULL; -+ } -+ -+ if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0)) -+ { -+ buffer->offset += 3; -+ } -+ -+ return buffer; -+} -+ -+CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated) -+{ -+ size_t buffer_length; -+ -+ if (NULL == value) -+ { -+ return NULL; -+ } -+ -+ /* Adding null character size due to require_null_terminated. */ -+ buffer_length = strlen(value) + sizeof(""); -+ -+ return cJSON_ParseWithLengthOpts(value, buffer_length, return_parse_end, require_null_terminated); -+} -+ -+/* Parse an object - create a new root, and populate. */ -+CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated) -+{ -+ parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; -+ cJSON *item = NULL; -+ -+ /* reset error position */ -+ global_error.json = NULL; -+ global_error.position = 0; -+ -+ if (value == NULL || 0 == buffer_length) -+ { -+ goto fail; -+ } -+ -+ buffer.content = (const unsigned char*)value; -+ buffer.length = buffer_length; -+ buffer.offset = 0; -+ buffer.hooks = global_hooks; -+ -+ item = cJSON_New_Item(&global_hooks); -+ if (item == NULL) /* memory fail */ -+ { -+ goto fail; -+ } -+ -+ if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)))) -+ { -+ /* parse failure. ep is set. */ -+ goto fail; -+ } -+ -+ /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ -+ if (require_null_terminated) -+ { -+ buffer_skip_whitespace(&buffer); -+ if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0') -+ { -+ goto fail; -+ } -+ } -+ if (return_parse_end) -+ { -+ *return_parse_end = (const char*)buffer_at_offset(&buffer); -+ } -+ -+ return item; -+ -+fail: -+ if (item != NULL) -+ { -+ cJSON_Delete(item); -+ } -+ -+ if (value != NULL) -+ { -+ error local_error; -+ local_error.json = (const unsigned char*)value; -+ local_error.position = 0; -+ -+ if (buffer.offset < buffer.length) -+ { -+ local_error.position = buffer.offset; -+ } -+ else if (buffer.length > 0) -+ { -+ local_error.position = buffer.length - 1; -+ } -+ -+ if (return_parse_end != NULL) -+ { -+ *return_parse_end = (const char*)local_error.json + local_error.position; -+ } -+ -+ global_error = local_error; -+ } -+ -+ return NULL; -+} -+ -+/* Default options for cJSON_Parse */ -+CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value) -+{ -+ return cJSON_ParseWithOpts(value, 0, 0); -+} -+ -+CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length) -+{ -+ return cJSON_ParseWithLengthOpts(value, buffer_length, 0, 0); -+} -+ -+#define cjson_min(a, b) (((a) < (b)) ? (a) : (b)) -+ -+static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks) -+{ -+ static const size_t default_buffer_size = 256; -+ printbuffer buffer[1]; -+ unsigned char *printed = NULL; -+ -+ memset(buffer, 0, sizeof(buffer)); -+ -+ /* create buffer */ -+ buffer->buffer = (unsigned char*) hooks->allocate(default_buffer_size); -+ buffer->length = default_buffer_size; -+ buffer->format = format; -+ buffer->hooks = *hooks; -+ if (buffer->buffer == NULL) -+ { -+ goto fail; -+ } -+ -+ /* print the value */ -+ if (!print_value(item, buffer)) -+ { -+ goto fail; -+ } -+ update_offset(buffer); -+ -+ /* check if reallocate is available */ -+ if (hooks->reallocate != NULL) -+ { -+ printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1); -+ if (printed == NULL) { -+ goto fail; -+ } -+ buffer->buffer = NULL; -+ } -+ else /* otherwise copy the JSON over to a new buffer */ -+ { -+ printed = (unsigned char*) hooks->allocate(buffer->offset + 1); -+ if (printed == NULL) -+ { -+ goto fail; -+ } -+ memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1)); -+ printed[buffer->offset] = '\0'; /* just to be sure */ -+ -+ /* free the buffer */ -+ hooks->deallocate(buffer->buffer); -+ } -+ -+ return printed; -+ -+fail: -+ if (buffer->buffer != NULL) -+ { -+ hooks->deallocate(buffer->buffer); -+ } -+ -+ if (printed != NULL) -+ { -+ hooks->deallocate(printed); -+ } -+ -+ return NULL; -+} -+ -+/* Render a cJSON item/entity/structure to text. */ -+CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item) -+{ -+ return (char*)print(item, true, &global_hooks); -+} -+ -+CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item) -+{ -+ return (char*)print(item, false, &global_hooks); -+} -+ -+CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt) -+{ -+ printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; -+ -+ if (prebuffer < 0) -+ { -+ return NULL; -+ } -+ -+ p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer); -+ if (!p.buffer) -+ { -+ return NULL; -+ } -+ -+ p.length = (size_t)prebuffer; -+ p.offset = 0; -+ p.noalloc = false; -+ p.format = fmt; -+ p.hooks = global_hooks; -+ -+ if (!print_value(item, &p)) -+ { -+ global_hooks.deallocate(p.buffer); -+ return NULL; -+ } -+ -+ return (char*)p.buffer; -+} -+ -+CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format) -+{ -+ printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; -+ -+ if ((length < 0) || (buffer == NULL)) -+ { -+ return false; -+ } -+ -+ p.buffer = (unsigned char*)buffer; -+ p.length = (size_t)length; -+ p.offset = 0; -+ p.noalloc = true; -+ p.format = format; -+ p.hooks = global_hooks; -+ -+ return print_value(item, &p); -+} -+ -+/* Parser core - when encountering text, process appropriately. */ -+static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer) -+{ -+ if ((input_buffer == NULL) || (input_buffer->content == NULL)) -+ { -+ return false; /* no input */ -+ } -+ -+ /* parse the different types of values */ -+ /* null */ -+ if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0)) -+ { -+ item->type = cJSON_NULL; -+ input_buffer->offset += 4; -+ return true; -+ } -+ /* false */ -+ if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0)) -+ { -+ item->type = cJSON_False; -+ input_buffer->offset += 5; -+ return true; -+ } -+ /* true */ -+ if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0)) -+ { -+ item->type = cJSON_True; -+ item->valueint = 1; -+ input_buffer->offset += 4; -+ return true; -+ } -+ /* string */ -+ if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) -+ { -+ return parse_string(item, input_buffer); -+ } -+ /* number */ -+ if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))) -+ { -+ return parse_number(item, input_buffer); -+ } -+ /* array */ -+ if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) -+ { -+ return parse_array(item, input_buffer); -+ } -+ /* object */ -+ if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) -+ { -+ return parse_object(item, input_buffer); -+ } -+ -+ return false; -+} -+ -+/* Render a value to text. */ -+static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer) -+{ -+ unsigned char *output = NULL; -+ -+ if ((item == NULL) || (output_buffer == NULL)) -+ { -+ return false; -+ } -+ -+ switch ((item->type) & 0xFF) -+ { -+ case cJSON_NULL: -+ output = ensure(output_buffer, 5); -+ if (output == NULL) -+ { -+ return false; -+ } -+ strcpy((char*)output, "null"); -+ return true; -+ -+ case cJSON_False: -+ output = ensure(output_buffer, 6); -+ if (output == NULL) -+ { -+ return false; -+ } -+ strcpy((char*)output, "false"); -+ return true; -+ -+ case cJSON_True: -+ output = ensure(output_buffer, 5); -+ if (output == NULL) -+ { -+ return false; -+ } -+ strcpy((char*)output, "true"); -+ return true; -+ -+ case cJSON_Number: -+ return print_number(item, output_buffer); -+ -+ case cJSON_Raw: -+ { -+ size_t raw_length = 0; -+ if (item->valuestring == NULL) -+ { -+ return false; -+ } -+ -+ raw_length = strlen(item->valuestring) + sizeof(""); -+ output = ensure(output_buffer, raw_length); -+ if (output == NULL) -+ { -+ return false; -+ } -+ memcpy(output, item->valuestring, raw_length); -+ return true; -+ } -+ -+ case cJSON_String: -+ return print_string(item, output_buffer); -+ -+ case cJSON_Array: -+ return print_array(item, output_buffer); -+ -+ case cJSON_Object: -+ return print_object(item, output_buffer); -+ -+ default: -+ return false; -+ } -+} -+ -+/* Build an array from input text. */ -+static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer) -+{ -+ cJSON *head = NULL; /* head of the linked list */ -+ cJSON *current_item = NULL; -+ -+ if (input_buffer->depth >= CJSON_NESTING_LIMIT) -+ { -+ return false; /* to deeply nested */ -+ } -+ input_buffer->depth++; -+ -+ if (buffer_at_offset(input_buffer)[0] != '[') -+ { -+ /* not an array */ -+ goto fail; -+ } -+ -+ input_buffer->offset++; -+ buffer_skip_whitespace(input_buffer); -+ if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) -+ { -+ /* empty array */ -+ goto success; -+ } -+ -+ /* check if we skipped to the end of the buffer */ -+ if (cannot_access_at_index(input_buffer, 0)) -+ { -+ input_buffer->offset--; -+ goto fail; -+ } -+ -+ /* step back to character in front of the first element */ -+ input_buffer->offset--; -+ /* loop through the comma separated array elements */ -+ do -+ { -+ /* allocate next item */ -+ cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); -+ if (new_item == NULL) -+ { -+ goto fail; /* allocation failure */ -+ } -+ -+ /* attach next item to list */ -+ if (head == NULL) -+ { -+ /* start the linked list */ -+ current_item = head = new_item; -+ } -+ else -+ { -+ /* add to the end and advance */ -+ current_item->next = new_item; -+ new_item->prev = current_item; -+ current_item = new_item; -+ } -+ -+ /* parse next value */ -+ input_buffer->offset++; -+ buffer_skip_whitespace(input_buffer); -+ if (!parse_value(current_item, input_buffer)) -+ { -+ goto fail; /* failed to parse value */ -+ } -+ buffer_skip_whitespace(input_buffer); -+ } -+ while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); -+ -+ if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') -+ { -+ goto fail; /* expected end of array */ -+ } -+ -+success: -+ input_buffer->depth--; -+ -+ if (head != NULL) { -+ head->prev = current_item; -+ } -+ -+ item->type = cJSON_Array; -+ item->child = head; -+ -+ input_buffer->offset++; -+ -+ return true; -+ -+fail: -+ if (head != NULL) -+ { -+ cJSON_Delete(head); -+ } -+ -+ return false; -+} -+ -+/* Render an array to text */ -+static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer) -+{ -+ unsigned char *output_pointer = NULL; -+ size_t length = 0; -+ cJSON *current_element = item->child; -+ -+ if (output_buffer == NULL) -+ { -+ return false; -+ } -+ -+ /* Compose the output array. */ -+ /* opening square bracket */ -+ output_pointer = ensure(output_buffer, 1); -+ if (output_pointer == NULL) -+ { -+ return false; -+ } -+ -+ *output_pointer = '['; -+ output_buffer->offset++; -+ output_buffer->depth++; -+ -+ while (current_element != NULL) -+ { -+ if (!print_value(current_element, output_buffer)) -+ { -+ return false; -+ } -+ update_offset(output_buffer); -+ if (current_element->next) -+ { -+ length = (size_t) (output_buffer->format ? 2 : 1); -+ output_pointer = ensure(output_buffer, length + 1); -+ if (output_pointer == NULL) -+ { -+ return false; -+ } -+ *output_pointer++ = ','; -+ if(output_buffer->format) -+ { -+ *output_pointer++ = ' '; -+ } -+ *output_pointer = '\0'; -+ output_buffer->offset += length; -+ } -+ current_element = current_element->next; -+ } -+ -+ output_pointer = ensure(output_buffer, 2); -+ if (output_pointer == NULL) -+ { -+ return false; -+ } -+ *output_pointer++ = ']'; -+ *output_pointer = '\0'; -+ output_buffer->depth--; -+ -+ return true; -+} -+ -+/* Build an object from the text. */ -+static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer) -+{ -+ cJSON *head = NULL; /* linked list head */ -+ cJSON *current_item = NULL; -+ -+ if (input_buffer->depth >= CJSON_NESTING_LIMIT) -+ { -+ return false; /* to deeply nested */ -+ } -+ input_buffer->depth++; -+ -+ if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')) -+ { -+ goto fail; /* not an object */ -+ } -+ -+ input_buffer->offset++; -+ buffer_skip_whitespace(input_buffer); -+ if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) -+ { -+ goto success; /* empty object */ -+ } -+ -+ /* check if we skipped to the end of the buffer */ -+ if (cannot_access_at_index(input_buffer, 0)) -+ { -+ input_buffer->offset--; -+ goto fail; -+ } -+ -+ /* step back to character in front of the first element */ -+ input_buffer->offset--; -+ /* loop through the comma separated array elements */ -+ do -+ { -+ /* allocate next item */ -+ cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); -+ if (new_item == NULL) -+ { -+ goto fail; /* allocation failure */ -+ } -+ -+ /* attach next item to list */ -+ if (head == NULL) -+ { -+ /* start the linked list */ -+ current_item = head = new_item; -+ } -+ else -+ { -+ /* add to the end and advance */ -+ current_item->next = new_item; -+ new_item->prev = current_item; -+ current_item = new_item; -+ } -+ -+ /* parse the name of the child */ -+ input_buffer->offset++; -+ buffer_skip_whitespace(input_buffer); -+ if (!parse_string(current_item, input_buffer)) -+ { -+ goto fail; /* failed to parse name */ -+ } -+ buffer_skip_whitespace(input_buffer); -+ -+ /* swap valuestring and string, because we parsed the name */ -+ current_item->string = current_item->valuestring; -+ current_item->valuestring = NULL; -+ -+ if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) -+ { -+ goto fail; /* invalid object */ -+ } -+ -+ /* parse the value */ -+ input_buffer->offset++; -+ buffer_skip_whitespace(input_buffer); -+ if (!parse_value(current_item, input_buffer)) -+ { -+ goto fail; /* failed to parse value */ -+ } -+ buffer_skip_whitespace(input_buffer); -+ } -+ while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); -+ -+ if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) -+ { -+ goto fail; /* expected end of object */ -+ } -+ -+success: -+ input_buffer->depth--; -+ -+ if (head != NULL) { -+ head->prev = current_item; -+ } -+ -+ item->type = cJSON_Object; -+ item->child = head; -+ -+ input_buffer->offset++; -+ return true; -+ -+fail: -+ if (head != NULL) -+ { -+ cJSON_Delete(head); -+ } -+ -+ return false; -+} -+ -+/* Render an object to text. */ -+static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer) -+{ -+ unsigned char *output_pointer = NULL; -+ size_t length = 0; -+ cJSON *current_item = item->child; -+ -+ if (output_buffer == NULL) -+ { -+ return false; -+ } -+ -+ /* Compose the output: */ -+ length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */ -+ output_pointer = ensure(output_buffer, length + 1); -+ if (output_pointer == NULL) -+ { -+ return false; -+ } -+ -+ *output_pointer++ = '{'; -+ output_buffer->depth++; -+ if (output_buffer->format) -+ { -+ *output_pointer++ = '\n'; -+ } -+ output_buffer->offset += length; -+ -+ while (current_item) -+ { -+ if (output_buffer->format) -+ { -+ size_t i; -+ output_pointer = ensure(output_buffer, output_buffer->depth); -+ if (output_pointer == NULL) -+ { -+ return false; -+ } -+ for (i = 0; i < output_buffer->depth; i++) -+ { -+ *output_pointer++ = '\t'; -+ } -+ output_buffer->offset += output_buffer->depth; -+ } -+ -+ /* print key */ -+ if (!print_string_ptr((unsigned char*)current_item->string, output_buffer)) -+ { -+ return false; -+ } -+ update_offset(output_buffer); -+ -+ length = (size_t) (output_buffer->format ? 2 : 1); -+ output_pointer = ensure(output_buffer, length); -+ if (output_pointer == NULL) -+ { -+ return false; -+ } -+ *output_pointer++ = ':'; -+ if (output_buffer->format) -+ { -+ *output_pointer++ = '\t'; -+ } -+ output_buffer->offset += length; -+ -+ /* print value */ -+ if (!print_value(current_item, output_buffer)) -+ { -+ return false; -+ } -+ update_offset(output_buffer); -+ -+ /* print comma if not last */ -+ length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0)); -+ output_pointer = ensure(output_buffer, length + 1); -+ if (output_pointer == NULL) -+ { -+ return false; -+ } -+ if (current_item->next) -+ { -+ *output_pointer++ = ','; -+ } -+ -+ if (output_buffer->format) -+ { -+ *output_pointer++ = '\n'; -+ } -+ *output_pointer = '\0'; -+ output_buffer->offset += length; -+ -+ current_item = current_item->next; -+ } -+ -+ output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2); -+ if (output_pointer == NULL) -+ { -+ return false; -+ } -+ if (output_buffer->format) -+ { -+ size_t i; -+ for (i = 0; i < (output_buffer->depth - 1); i++) -+ { -+ *output_pointer++ = '\t'; -+ } -+ } -+ *output_pointer++ = '}'; -+ *output_pointer = '\0'; -+ output_buffer->depth--; -+ -+ return true; -+} -+ -+/* Get Array size/item / object item. */ -+CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array) -+{ -+ cJSON *child = NULL; -+ size_t size = 0; -+ -+ if (array == NULL) -+ { -+ return 0; -+ } -+ -+ child = array->child; -+ -+ while(child != NULL) -+ { -+ size++; -+ child = child->next; -+ } -+ -+ /* FIXME: Can overflow here. Cannot be fixed without breaking the API */ -+ -+ return (int)size; -+} -+ -+static cJSON* get_array_item(const cJSON *array, size_t index) -+{ -+ cJSON *current_child = NULL; -+ -+ if (array == NULL) -+ { -+ return NULL; -+ } -+ -+ current_child = array->child; -+ while ((current_child != NULL) && (index > 0)) -+ { -+ index--; -+ current_child = current_child->next; -+ } -+ -+ return current_child; -+} -+ -+CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index) -+{ -+ if (index < 0) -+ { -+ return NULL; -+ } -+ -+ return get_array_item(array, (size_t)index); -+} -+ -+static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive) -+{ -+ cJSON *current_element = NULL; -+ -+ if ((object == NULL) || (name == NULL)) -+ { -+ return NULL; -+ } -+ -+ current_element = object->child; -+ if (case_sensitive) -+ { -+ while ((current_element != NULL) && (current_element->string != NULL) && (strcmp(name, current_element->string) != 0)) -+ { -+ current_element = current_element->next; -+ } -+ } -+ else -+ { -+ while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0)) -+ { -+ current_element = current_element->next; -+ } -+ } -+ -+ if ((current_element == NULL) || (current_element->string == NULL)) { -+ return NULL; -+ } -+ -+ return current_element; -+} -+ -+CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string) -+{ -+ return get_object_item(object, string, false); -+} -+ -+CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string) -+{ -+ return get_object_item(object, string, true); -+} -+ -+CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string) -+{ -+ return cJSON_GetObjectItem(object, string) ? 1 : 0; -+} -+ -+/* Utility for array list handling. */ -+static void suffix_object(cJSON *prev, cJSON *item) -+{ -+ prev->next = item; -+ item->prev = prev; -+} -+ -+/* Utility for handling references. */ -+static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks) -+{ -+ cJSON *reference = NULL; -+ if (item == NULL) -+ { -+ return NULL; -+ } -+ -+ reference = cJSON_New_Item(hooks); -+ if (reference == NULL) -+ { -+ return NULL; -+ } -+ -+ memcpy(reference, item, sizeof(cJSON)); -+ reference->string = NULL; -+ reference->type |= cJSON_IsReference; -+ reference->next = reference->prev = NULL; -+ return reference; -+} -+ -+static cJSON_bool add_item_to_array(cJSON *array, cJSON *item) -+{ -+ cJSON *child = NULL; -+ -+ if ((item == NULL) || (array == NULL) || (array == item)) -+ { -+ return false; -+ } -+ -+ child = array->child; -+ /* -+ * To find the last item in array quickly, we use prev in array -+ */ -+ if (child == NULL) -+ { -+ /* list is empty, start new one */ -+ array->child = item; -+ item->prev = item; -+ item->next = NULL; -+ } -+ else -+ { -+ /* append to the end */ -+ if (child->prev) -+ { -+ suffix_object(child->prev, item); -+ array->child->prev = item; -+ } -+ } -+ -+ return true; -+} -+ -+/* Add item to array/object. */ -+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item) -+{ -+ return add_item_to_array(array, item); -+} -+ -+#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) -+ #pragma GCC diagnostic push -+#endif -+#ifdef __GNUC__ -+#pragma GCC diagnostic ignored "-Wcast-qual" -+#endif -+/* helper function to cast away const */ -+static void* cast_away_const(const void* string) -+{ -+ return (void*)string; -+} -+#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) -+ #pragma GCC diagnostic pop -+#endif -+ -+ -+static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_hooks * const hooks, const cJSON_bool constant_key) -+{ -+ char *new_key = NULL; -+ int new_type = cJSON_Invalid; -+ -+ if ((object == NULL) || (string == NULL) || (item == NULL) || (object == item)) -+ { -+ return false; -+ } -+ -+ if (constant_key) -+ { -+ new_key = (char*)cast_away_const(string); -+ new_type = item->type | cJSON_StringIsConst; -+ } -+ else -+ { -+ new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks); -+ if (new_key == NULL) -+ { -+ return false; -+ } -+ -+ new_type = item->type & ~cJSON_StringIsConst; -+ } -+ -+ if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) -+ { -+ hooks->deallocate(item->string); -+ } -+ -+ item->string = new_key; -+ item->type = new_type; -+ -+ return add_item_to_array(object, item); -+} -+ -+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) -+{ -+ return add_item_to_object(object, string, item, &global_hooks, false); -+} -+ -+/* Add an item to an object with constant string as key */ -+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) -+{ -+ return add_item_to_object(object, string, item, &global_hooks, true); -+} -+ -+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) -+{ -+ if (array == NULL) -+ { -+ return false; -+ } -+ -+ return add_item_to_array(array, create_reference(item, &global_hooks)); -+} -+ -+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) -+{ -+ if ((object == NULL) || (string == NULL)) -+ { -+ return false; -+ } -+ -+ return add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false); -+} -+ -+CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name) -+{ -+ cJSON *null = cJSON_CreateNull(); -+ if (add_item_to_object(object, name, null, &global_hooks, false)) -+ { -+ return null; -+ } -+ -+ cJSON_Delete(null); -+ return NULL; -+} -+ -+CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name) -+{ -+ cJSON *true_item = cJSON_CreateTrue(); -+ if (add_item_to_object(object, name, true_item, &global_hooks, false)) -+ { -+ return true_item; -+ } -+ -+ cJSON_Delete(true_item); -+ return NULL; -+} -+ -+CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name) -+{ -+ cJSON *false_item = cJSON_CreateFalse(); -+ if (add_item_to_object(object, name, false_item, &global_hooks, false)) -+ { -+ return false_item; -+ } -+ -+ cJSON_Delete(false_item); -+ return NULL; -+} -+ -+CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean) -+{ -+ cJSON *bool_item = cJSON_CreateBool(boolean); -+ if (add_item_to_object(object, name, bool_item, &global_hooks, false)) -+ { -+ return bool_item; -+ } -+ -+ cJSON_Delete(bool_item); -+ return NULL; -+} -+ -+CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number) -+{ -+ cJSON *number_item = cJSON_CreateNumber(number); -+ if (add_item_to_object(object, name, number_item, &global_hooks, false)) -+ { -+ return number_item; -+ } -+ -+ cJSON_Delete(number_item); -+ return NULL; -+} -+ -+CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string) -+{ -+ cJSON *string_item = cJSON_CreateString(string); -+ if (add_item_to_object(object, name, string_item, &global_hooks, false)) -+ { -+ return string_item; -+ } -+ -+ cJSON_Delete(string_item); -+ return NULL; -+} -+ -+CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw) -+{ -+ cJSON *raw_item = cJSON_CreateRaw(raw); -+ if (add_item_to_object(object, name, raw_item, &global_hooks, false)) -+ { -+ return raw_item; -+ } -+ -+ cJSON_Delete(raw_item); -+ return NULL; -+} -+ -+CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name) -+{ -+ cJSON *object_item = cJSON_CreateObject(); -+ if (add_item_to_object(object, name, object_item, &global_hooks, false)) -+ { -+ return object_item; -+ } -+ -+ cJSON_Delete(object_item); -+ return NULL; -+} -+ -+CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name) -+{ -+ cJSON *array = cJSON_CreateArray(); -+ if (add_item_to_object(object, name, array, &global_hooks, false)) -+ { -+ return array; -+ } -+ -+ cJSON_Delete(array); -+ return NULL; -+} -+ -+CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item) -+{ -+ if ((parent == NULL) || (item == NULL)) -+ { -+ return NULL; -+ } -+ -+ if (item != parent->child) -+ { -+ /* not the first element */ -+ item->prev->next = item->next; -+ } -+ if (item->next != NULL) -+ { -+ /* not the last element */ -+ item->next->prev = item->prev; -+ } -+ -+ if (item == parent->child) -+ { -+ /* first element */ -+ parent->child = item->next; -+ } -+ else if (item->next == NULL) -+ { -+ /* last element */ -+ parent->child->prev = item->prev; -+ } -+ -+ /* make sure the detached item doesn't point anywhere anymore */ -+ item->prev = NULL; -+ item->next = NULL; -+ -+ return item; -+} -+ -+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which) -+{ -+ if (which < 0) -+ { -+ return NULL; -+ } -+ -+ return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which)); -+} -+ -+CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which) -+{ -+ cJSON_Delete(cJSON_DetachItemFromArray(array, which)); -+} -+ -+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string) -+{ -+ cJSON *to_detach = cJSON_GetObjectItem(object, string); -+ -+ return cJSON_DetachItemViaPointer(object, to_detach); -+} -+ -+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string) -+{ -+ cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string); -+ -+ return cJSON_DetachItemViaPointer(object, to_detach); -+} -+ -+CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string) -+{ -+ cJSON_Delete(cJSON_DetachItemFromObject(object, string)); -+} -+ -+CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string) -+{ -+ cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string)); -+} -+ -+/* Replace array/object items with new ones. */ -+CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) -+{ -+ cJSON *after_inserted = NULL; -+ -+ if (which < 0) -+ { -+ return false; -+ } -+ -+ after_inserted = get_array_item(array, (size_t)which); -+ if (after_inserted == NULL) -+ { -+ return add_item_to_array(array, newitem); -+ } -+ -+ newitem->next = after_inserted; -+ newitem->prev = after_inserted->prev; -+ after_inserted->prev = newitem; -+ if (after_inserted == array->child) -+ { -+ array->child = newitem; -+ } -+ else -+ { -+ newitem->prev->next = newitem; -+ } -+ return true; -+} -+ -+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement) -+{ -+ if ((parent == NULL) || (replacement == NULL) || (item == NULL)) -+ { -+ return false; -+ } -+ -+ if (replacement == item) -+ { -+ return true; -+ } -+ -+ replacement->next = item->next; -+ replacement->prev = item->prev; -+ -+ if (replacement->next != NULL) -+ { -+ replacement->next->prev = replacement; -+ } -+ if (parent->child == item) -+ { -+ if (parent->child->prev == parent->child) -+ { -+ replacement->prev = replacement; -+ } -+ parent->child = replacement; -+ } -+ else -+ { /* -+ * To find the last item in array quickly, we use prev in array. -+ * We can't modify the last item's next pointer where this item was the parent's child -+ */ -+ if (replacement->prev != NULL) -+ { -+ replacement->prev->next = replacement; -+ } -+ if (replacement->next == NULL) -+ { -+ parent->child->prev = replacement; -+ } -+ } -+ -+ item->next = NULL; -+ item->prev = NULL; -+ cJSON_Delete(item); -+ -+ return true; -+} -+ -+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) -+{ -+ if (which < 0) -+ { -+ return false; -+ } -+ -+ return cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem); -+} -+ -+static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive) -+{ -+ if ((replacement == NULL) || (string == NULL)) -+ { -+ return false; -+ } -+ -+ /* replace the name in the replacement */ -+ if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL)) -+ { -+ cJSON_free(replacement->string); -+ } -+ replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); -+ if (replacement->string == NULL) -+ { -+ return false; -+ } -+ -+ replacement->type &= ~cJSON_StringIsConst; -+ -+ return cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement); -+} -+ -+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) -+{ -+ return replace_item_in_object(object, string, newitem, false); -+} -+ -+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem) -+{ -+ return replace_item_in_object(object, string, newitem, true); -+} -+ -+/* Create basic types: */ -+CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void) -+{ -+ cJSON *item = cJSON_New_Item(&global_hooks); -+ if(item) -+ { -+ item->type = cJSON_NULL; -+ } -+ -+ return item; -+} -+ -+CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void) -+{ -+ cJSON *item = cJSON_New_Item(&global_hooks); -+ if(item) -+ { -+ item->type = cJSON_True; -+ } -+ -+ return item; -+} -+ -+CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void) -+{ -+ cJSON *item = cJSON_New_Item(&global_hooks); -+ if(item) -+ { -+ item->type = cJSON_False; -+ } -+ -+ return item; -+} -+ -+CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean) -+{ -+ cJSON *item = cJSON_New_Item(&global_hooks); -+ if(item) -+ { -+ item->type = boolean ? cJSON_True : cJSON_False; -+ } -+ -+ return item; -+} -+ -+CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num) -+{ -+ cJSON *item = cJSON_New_Item(&global_hooks); -+ if(item) -+ { -+ item->type = cJSON_Number; -+ item->valuedouble = num; -+ -+ /* use saturation in case of overflow */ -+ if (num >= INT_MAX) -+ { -+ item->valueint = INT_MAX; -+ } -+ else if (num <= (double)INT_MIN) -+ { -+ item->valueint = INT_MIN; -+ } -+ else -+ { -+ item->valueint = (int)num; -+ } -+ } -+ -+ return item; -+} -+ -+CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string) -+{ -+ cJSON *item = cJSON_New_Item(&global_hooks); -+ if(item) -+ { -+ item->type = cJSON_String; -+ item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); -+ if(!item->valuestring) -+ { -+ cJSON_Delete(item); -+ return NULL; -+ } -+ } -+ -+ return item; -+} -+ -+CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string) -+{ -+ cJSON *item = cJSON_New_Item(&global_hooks); -+ if (item != NULL) -+ { -+ item->type = cJSON_String | cJSON_IsReference; -+ item->valuestring = (char*)cast_away_const(string); -+ } -+ -+ return item; -+} -+ -+CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child) -+{ -+ cJSON *item = cJSON_New_Item(&global_hooks); -+ if (item != NULL) { -+ item->type = cJSON_Object | cJSON_IsReference; -+ item->child = (cJSON*)cast_away_const(child); -+ } -+ -+ return item; -+} -+ -+CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) { -+ cJSON *item = cJSON_New_Item(&global_hooks); -+ if (item != NULL) { -+ item->type = cJSON_Array | cJSON_IsReference; -+ item->child = (cJSON*)cast_away_const(child); -+ } -+ -+ return item; -+} -+ -+CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) -+{ -+ cJSON *item = cJSON_New_Item(&global_hooks); -+ if(item) -+ { -+ item->type = cJSON_Raw; -+ item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks); -+ if(!item->valuestring) -+ { -+ cJSON_Delete(item); -+ return NULL; -+ } -+ } -+ -+ return item; -+} -+ -+CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void) -+{ -+ cJSON *item = cJSON_New_Item(&global_hooks); -+ if(item) -+ { -+ item->type=cJSON_Array; -+ } -+ -+ return item; -+} -+ -+CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void) -+{ -+ cJSON *item = cJSON_New_Item(&global_hooks); -+ if (item) -+ { -+ item->type = cJSON_Object; -+ } -+ -+ return item; -+} -+ -+/* Create Arrays: */ -+CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) -+{ -+ size_t i = 0; -+ cJSON *n = NULL; -+ cJSON *p = NULL; -+ cJSON *a = NULL; -+ -+ if ((count < 0) || (numbers == NULL)) -+ { -+ return NULL; -+ } -+ -+ a = cJSON_CreateArray(); -+ -+ for(i = 0; a && (i < (size_t)count); i++) -+ { -+ n = cJSON_CreateNumber(numbers[i]); -+ if (!n) -+ { -+ cJSON_Delete(a); -+ return NULL; -+ } -+ if(!i) -+ { -+ a->child = n; -+ } -+ else -+ { -+ suffix_object(p, n); -+ } -+ p = n; -+ } -+ -+ if (a && a->child) { -+ a->child->prev = n; -+ } -+ -+ return a; -+} -+ -+CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count) -+{ -+ size_t i = 0; -+ cJSON *n = NULL; -+ cJSON *p = NULL; -+ cJSON *a = NULL; -+ -+ if ((count < 0) || (numbers == NULL)) -+ { -+ return NULL; -+ } -+ -+ a = cJSON_CreateArray(); -+ -+ for(i = 0; a && (i < (size_t)count); i++) -+ { -+ n = cJSON_CreateNumber((double)numbers[i]); -+ if(!n) -+ { -+ cJSON_Delete(a); -+ return NULL; -+ } -+ if(!i) -+ { -+ a->child = n; -+ } -+ else -+ { -+ suffix_object(p, n); -+ } -+ p = n; -+ } -+ -+ if (a && a->child) { -+ a->child->prev = n; -+ } -+ -+ return a; -+} -+ -+CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) -+{ -+ size_t i = 0; -+ cJSON *n = NULL; -+ cJSON *p = NULL; -+ cJSON *a = NULL; -+ -+ if ((count < 0) || (numbers == NULL)) -+ { -+ return NULL; -+ } -+ -+ a = cJSON_CreateArray(); -+ -+ for(i = 0; a && (i < (size_t)count); i++) -+ { -+ n = cJSON_CreateNumber(numbers[i]); -+ if(!n) -+ { -+ cJSON_Delete(a); -+ return NULL; -+ } -+ if(!i) -+ { -+ a->child = n; -+ } -+ else -+ { -+ suffix_object(p, n); -+ } -+ p = n; -+ } -+ -+ if (a && a->child) { -+ a->child->prev = n; -+ } -+ -+ return a; -+} -+ -+CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count) -+{ -+ size_t i = 0; -+ cJSON *n = NULL; -+ cJSON *p = NULL; -+ cJSON *a = NULL; -+ -+ if ((count < 0) || (strings == NULL)) -+ { -+ return NULL; -+ } -+ -+ a = cJSON_CreateArray(); -+ -+ for (i = 0; a && (i < (size_t)count); i++) -+ { -+ n = cJSON_CreateString(strings[i]); -+ if(!n) -+ { -+ cJSON_Delete(a); -+ return NULL; -+ } -+ if(!i) -+ { -+ a->child = n; -+ } -+ else -+ { -+ suffix_object(p,n); -+ } -+ p = n; -+ } -+ -+ if (a && a->child) { -+ a->child->prev = n; -+ } -+ -+ return a; -+} -+ -+/* Duplication */ -+CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) -+{ -+ cJSON *newitem = NULL; -+ cJSON *child = NULL; -+ cJSON *next = NULL; -+ cJSON *newchild = NULL; -+ -+ /* Bail on bad ptr */ -+ if (!item) -+ { -+ goto fail; -+ } -+ /* Create new item */ -+ newitem = cJSON_New_Item(&global_hooks); -+ if (!newitem) -+ { -+ goto fail; -+ } -+ /* Copy over all vars */ -+ newitem->type = item->type & (~cJSON_IsReference); -+ newitem->valueint = item->valueint; -+ newitem->valuedouble = item->valuedouble; -+ if (item->valuestring) -+ { -+ newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks); -+ if (!newitem->valuestring) -+ { -+ goto fail; -+ } -+ } -+ if (item->string) -+ { -+ newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks); -+ if (!newitem->string) -+ { -+ goto fail; -+ } -+ } -+ /* If non-recursive, then we're done! */ -+ if (!recurse) -+ { -+ return newitem; -+ } -+ /* Walk the ->next chain for the child. */ -+ child = item->child; -+ while (child != NULL) -+ { -+ newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */ -+ if (!newchild) -+ { -+ goto fail; -+ } -+ if (next != NULL) -+ { -+ /* If newitem->child already set, then crosswire ->prev and ->next and move on */ -+ next->next = newchild; -+ newchild->prev = next; -+ next = newchild; -+ } -+ else -+ { -+ /* Set newitem->child and move to it */ -+ newitem->child = newchild; -+ next = newchild; -+ } -+ child = child->next; -+ } -+ if (newitem && newitem->child) -+ { -+ newitem->child->prev = newchild; -+ } -+ -+ return newitem; -+ -+fail: -+ if (newitem != NULL) -+ { -+ cJSON_Delete(newitem); -+ } -+ -+ return NULL; -+} -+ -+static void skip_oneline_comment(char **input) -+{ -+ *input += static_strlen("//"); -+ -+ for (; (*input)[0] != '\0'; ++(*input)) -+ { -+ if ((*input)[0] == '\n') { -+ *input += static_strlen("\n"); -+ return; -+ } -+ } -+} -+ -+static void skip_multiline_comment(char **input) -+{ -+ *input += static_strlen("/*"); -+ -+ for (; (*input)[0] != '\0'; ++(*input)) -+ { -+ if (((*input)[0] == '*') && ((*input)[1] == '/')) -+ { -+ *input += static_strlen("*/"); -+ return; -+ } -+ } -+} -+ -+static void minify_string(char **input, char **output) { -+ (*output)[0] = (*input)[0]; -+ *input += static_strlen("\""); -+ *output += static_strlen("\""); -+ -+ -+ for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) { -+ (*output)[0] = (*input)[0]; -+ -+ if ((*input)[0] == '\"') { -+ (*output)[0] = '\"'; -+ *input += static_strlen("\""); -+ *output += static_strlen("\""); -+ return; -+ } else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) { -+ (*output)[1] = (*input)[1]; -+ *input += static_strlen("\""); -+ *output += static_strlen("\""); -+ } -+ } -+} -+ -+CJSON_PUBLIC(void) cJSON_Minify(char *json) -+{ -+ char *into = json; -+ -+ if (json == NULL) -+ { -+ return; -+ } -+ -+ while (json[0] != '\0') -+ { -+ switch (json[0]) -+ { -+ case ' ': -+ case '\t': -+ case '\r': -+ case '\n': -+ json++; -+ break; -+ -+ case '/': -+ if (json[1] == '/') -+ { -+ skip_oneline_comment(&json); -+ } -+ else if (json[1] == '*') -+ { -+ skip_multiline_comment(&json); -+ } else { -+ json++; -+ } -+ break; -+ -+ case '\"': -+ minify_string(&json, (char**)&into); -+ break; -+ -+ default: -+ into[0] = json[0]; -+ json++; -+ into++; -+ } -+ } -+ -+ /* and null-terminate. */ -+ *into = '\0'; -+} -+ -+CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item) -+{ -+ if (item == NULL) -+ { -+ return false; -+ } -+ -+ return (item->type & 0xFF) == cJSON_Invalid; -+} -+ -+CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item) -+{ -+ if (item == NULL) -+ { -+ return false; -+ } -+ -+ return (item->type & 0xFF) == cJSON_False; -+} -+ -+CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item) -+{ -+ if (item == NULL) -+ { -+ return false; -+ } -+ -+ return (item->type & 0xff) == cJSON_True; -+} -+ -+ -+CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item) -+{ -+ if (item == NULL) -+ { -+ return false; -+ } -+ -+ return (item->type & (cJSON_True | cJSON_False)) != 0; -+} -+CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item) -+{ -+ if (item == NULL) -+ { -+ return false; -+ } -+ -+ return (item->type & 0xFF) == cJSON_NULL; -+} -+ -+CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item) -+{ -+ if (item == NULL) -+ { -+ return false; -+ } -+ -+ return (item->type & 0xFF) == cJSON_Number; -+} -+ -+CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item) -+{ -+ if (item == NULL) -+ { -+ return false; -+ } -+ -+ return (item->type & 0xFF) == cJSON_String; -+} -+ -+CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item) -+{ -+ if (item == NULL) -+ { -+ return false; -+ } -+ -+ return (item->type & 0xFF) == cJSON_Array; -+} -+ -+CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item) -+{ -+ if (item == NULL) -+ { -+ return false; -+ } -+ -+ return (item->type & 0xFF) == cJSON_Object; -+} -+ -+CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item) -+{ -+ if (item == NULL) -+ { -+ return false; -+ } -+ -+ return (item->type & 0xFF) == cJSON_Raw; -+} -+ -+CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive) -+{ -+ if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF))) -+ { -+ return false; -+ } -+ -+ /* check if type is valid */ -+ switch (a->type & 0xFF) -+ { -+ case cJSON_False: -+ case cJSON_True: -+ case cJSON_NULL: -+ case cJSON_Number: -+ case cJSON_String: -+ case cJSON_Raw: -+ case cJSON_Array: -+ case cJSON_Object: -+ break; -+ -+ default: -+ return false; -+ } -+ -+ /* identical objects are equal */ -+ if (a == b) -+ { -+ return true; -+ } -+ -+ switch (a->type & 0xFF) -+ { -+ /* in these cases and equal type is enough */ -+ case cJSON_False: -+ case cJSON_True: -+ case cJSON_NULL: -+ return true; -+ -+ case cJSON_Number: -+ if (compare_double(a->valuedouble, b->valuedouble)) -+ { -+ return true; -+ } -+ return false; -+ -+ case cJSON_String: -+ case cJSON_Raw: -+ if ((a->valuestring == NULL) || (b->valuestring == NULL)) -+ { -+ return false; -+ } -+ if (strcmp(a->valuestring, b->valuestring) == 0) -+ { -+ return true; -+ } -+ -+ return false; -+ -+ case cJSON_Array: -+ { -+ cJSON *a_element = a->child; -+ cJSON *b_element = b->child; -+ -+ for (; (a_element != NULL) && (b_element != NULL);) -+ { -+ if (!cJSON_Compare(a_element, b_element, case_sensitive)) -+ { -+ return false; -+ } -+ -+ a_element = a_element->next; -+ b_element = b_element->next; -+ } -+ -+ /* one of the arrays is longer than the other */ -+ if (a_element != b_element) { -+ return false; -+ } -+ -+ return true; -+ } -+ -+ case cJSON_Object: -+ { -+ cJSON *a_element = NULL; -+ cJSON *b_element = NULL; -+ cJSON_ArrayForEach(a_element, a) -+ { -+ /* TODO This has O(n^2) runtime, which is horrible! */ -+ b_element = get_object_item(b, a_element->string, case_sensitive); -+ if (b_element == NULL) -+ { -+ return false; -+ } -+ -+ if (!cJSON_Compare(a_element, b_element, case_sensitive)) -+ { -+ return false; -+ } -+ } -+ -+ /* doing this twice, once on a and b to prevent true comparison if a subset of b -+ * TODO: Do this the proper way, this is just a fix for now */ -+ cJSON_ArrayForEach(b_element, b) -+ { -+ a_element = get_object_item(a, b_element->string, case_sensitive); -+ if (a_element == NULL) -+ { -+ return false; -+ } -+ -+ if (!cJSON_Compare(b_element, a_element, case_sensitive)) -+ { -+ return false; -+ } -+ } -+ -+ return true; -+ } -+ -+ default: -+ return false; -+ } -+} -+ -+CJSON_PUBLIC(void *) cJSON_malloc(size_t size) -+{ -+ return global_hooks.allocate(size); -+} -+ -+CJSON_PUBLIC(void) cJSON_free(void *object) -+{ -+ global_hooks.deallocate(object); -+} -diff --git a/qtfs/rexec/rshim/cJSON.h b/qtfs/rexec/rshim/cJSON.h -new file mode 100644 -index 0000000..95a9cf6 ---- /dev/null -+++ b/qtfs/rexec/rshim/cJSON.h -@@ -0,0 +1,300 @@ -+/* -+ Copyright (c) 2009-2017 Dave Gamble and cJSON contributors -+ -+ Permission is hereby granted, free of charge, to any person obtaining a copy -+ of this software and associated documentation files (the "Software"), to deal -+ in the Software without restriction, including without limitation the rights -+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ copies of the Software, and to permit persons to whom the Software is -+ furnished to do so, subject to the following conditions: -+ -+ The above copyright notice and this permission notice shall be included in -+ all copies or substantial portions of the Software. -+ -+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ THE SOFTWARE. -+*/ -+ -+#ifndef cJSON__h -+#define cJSON__h -+ -+#ifdef __cplusplus -+extern "C" -+{ -+#endif -+ -+#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) -+#define __WINDOWS__ -+#endif -+ -+#ifdef __WINDOWS__ -+ -+/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options: -+ -+CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols -+CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default) -+CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol -+ -+For *nix builds that support visibility attribute, you can define similar behavior by -+ -+setting default visibility to hidden by adding -+-fvisibility=hidden (for gcc) -+or -+-xldscope=hidden (for sun cc) -+to CFLAGS -+ -+then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does -+ -+*/ -+ -+#define CJSON_CDECL __cdecl -+#define CJSON_STDCALL __stdcall -+ -+/* export symbols by default, this is necessary for copy pasting the C and header file */ -+#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS) -+#define CJSON_EXPORT_SYMBOLS -+#endif -+ -+#if defined(CJSON_HIDE_SYMBOLS) -+#define CJSON_PUBLIC(type) type CJSON_STDCALL -+#elif defined(CJSON_EXPORT_SYMBOLS) -+#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL -+#elif defined(CJSON_IMPORT_SYMBOLS) -+#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL -+#endif -+#else /* !__WINDOWS__ */ -+#define CJSON_CDECL -+#define CJSON_STDCALL -+ -+#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY) -+#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type -+#else -+#define CJSON_PUBLIC(type) type -+#endif -+#endif -+ -+/* project version */ -+#define CJSON_VERSION_MAJOR 1 -+#define CJSON_VERSION_MINOR 7 -+#define CJSON_VERSION_PATCH 15 -+ -+#include -+ -+/* cJSON Types: */ -+#define cJSON_Invalid (0) -+#define cJSON_False (1 << 0) -+#define cJSON_True (1 << 1) -+#define cJSON_NULL (1 << 2) -+#define cJSON_Number (1 << 3) -+#define cJSON_String (1 << 4) -+#define cJSON_Array (1 << 5) -+#define cJSON_Object (1 << 6) -+#define cJSON_Raw (1 << 7) /* raw json */ -+ -+#define cJSON_IsReference 256 -+#define cJSON_StringIsConst 512 -+ -+/* The cJSON structure: */ -+typedef struct cJSON -+{ -+ /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ -+ struct cJSON *next; -+ struct cJSON *prev; -+ /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ -+ struct cJSON *child; -+ -+ /* The type of the item, as above. */ -+ int type; -+ -+ /* The item's string, if type==cJSON_String and type == cJSON_Raw */ -+ char *valuestring; -+ /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ -+ int valueint; -+ /* The item's number, if type==cJSON_Number */ -+ double valuedouble; -+ -+ /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ -+ char *string; -+} cJSON; -+ -+typedef struct cJSON_Hooks -+{ -+ /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */ -+ void *(CJSON_CDECL *malloc_fn)(size_t sz); -+ void (CJSON_CDECL *free_fn)(void *ptr); -+} cJSON_Hooks; -+ -+typedef int cJSON_bool; -+ -+/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them. -+ * This is to prevent stack overflows. */ -+#ifndef CJSON_NESTING_LIMIT -+#define CJSON_NESTING_LIMIT 1000 -+#endif -+ -+/* returns the version of cJSON as a string */ -+CJSON_PUBLIC(const char*) cJSON_Version(void); -+ -+/* Supply malloc, realloc and free functions to cJSON */ -+CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); -+ -+/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */ -+/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */ -+CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value); -+CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length); -+/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ -+/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */ -+CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated); -+CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated); -+ -+/* Render a cJSON entity to text for transfer/storage. */ -+CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item); -+/* Render a cJSON entity to text for transfer/storage without any formatting. */ -+CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item); -+/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ -+CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt); -+/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */ -+/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */ -+CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format); -+/* Delete a cJSON entity and all subentities. */ -+CJSON_PUBLIC(void) cJSON_Delete(cJSON *item); -+ -+/* Returns the number of items in an array (or object). */ -+CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array); -+/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */ -+CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index); -+/* Get item "string" from object. Case insensitive. */ -+CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string); -+CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string); -+CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string); -+/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ -+CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); -+ -+/* Check item type and return its value */ -+CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item); -+CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item); -+ -+/* These functions check the type of an item */ -+CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item); -+CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item); -+CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item); -+CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item); -+CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item); -+CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item); -+CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item); -+CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item); -+CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item); -+CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item); -+ -+/* These calls create a cJSON item of the appropriate type. */ -+CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void); -+CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void); -+CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void); -+CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean); -+CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num); -+CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string); -+/* raw json */ -+CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw); -+CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void); -+CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); -+ -+/* Create a string where valuestring references a string so -+ * it will not be freed by cJSON_Delete */ -+CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string); -+/* Create an object/array that only references it's elements so -+ * they will not be freed by cJSON_Delete */ -+CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child); -+CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child); -+ -+/* These utilities create an Array of count items. -+ * The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/ -+CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); -+CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count); -+CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count); -+CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count); -+ -+/* Append item to the specified array/object. */ -+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item); -+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); -+/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object. -+ * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before -+ * writing to `item->string` */ -+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); -+/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ -+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); -+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); -+ -+/* Remove/Detach items from Arrays/Objects. */ -+CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item); -+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which); -+CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which); -+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string); -+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string); -+CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string); -+CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string); -+ -+/* Update array items. */ -+CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ -+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement); -+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); -+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); -+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem); -+ -+/* Duplicate a cJSON item */ -+CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse); -+/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will -+ * need to be released. With recurse!=0, it will duplicate any children connected to the item. -+ * The item->next and ->prev pointers are always zero on return from Duplicate. */ -+/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal. -+ * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */ -+CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive); -+ -+/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings. -+ * The input pointer json cannot point to a read-only address area, such as a string constant, -+ * but should point to a readable and writable address area. */ -+CJSON_PUBLIC(void) cJSON_Minify(char *json); -+ -+/* Helper functions for creating and adding items to an object at the same time. -+ * They return the added item or NULL on failure. */ -+CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name); -+CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name); -+CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name); -+CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean); -+CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number); -+CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string); -+CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw); -+CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name); -+CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name); -+ -+/* When assigning an integer value, it needs to be propagated to valuedouble too. */ -+#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number)) -+/* helper for the cJSON_SetNumberValue macro */ -+CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number); -+#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number)) -+/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */ -+CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring); -+ -+/* If the object is not a boolean type this does nothing and returns cJSON_Invalid else it returns the new type*/ -+#define cJSON_SetBoolValue(object, boolValue) ( \ -+ (object != NULL && ((object)->type & (cJSON_False|cJSON_True))) ? \ -+ (object)->type=((object)->type &(~(cJSON_False|cJSON_True)))|((boolValue)?cJSON_True:cJSON_False) : \ -+ cJSON_Invalid\ -+) -+ -+/* Macro for iterating over an array or object */ -+#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) -+ -+/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */ -+CJSON_PUBLIC(void *) cJSON_malloc(size_t size); -+CJSON_PUBLIC(void) cJSON_free(void *object); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif -diff --git a/qtfs/rexec/rshim/rexec_shim.c b/qtfs/rexec/rshim/rexec_shim.c -new file mode 100644 -index 0000000..8e1b6ca ---- /dev/null -+++ b/qtfs/rexec/rshim/rexec_shim.c -@@ -0,0 +1,198 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "cJSON.h" -+ -+#include "dirent.h" -+ -+#define RSHIM_LOG_FILE "/var/run/rexec/rexec_shim.log" -+#define rshim_log(info, ...) \ -+ do { \ -+ time_t t; \ -+ struct tm *p; \ -+ time(&t); \ -+ p = localtime(&t); \ -+ printf("[%d/%02d/%02d %02d:%02d:%02d][LOG:%s:%3d]"info"\n", \ -+ p->tm_year + 1900, p->tm_mon+1, p->tm_mday, \ -+ p->tm_hour, p->tm_min, p->tm_sec, __func__, __LINE__, ##__VA_ARGS__); \ -+ } while (0); -+ -+#define rshim_err(info, ...) \ -+ do { \ -+ time_t t; \ -+ struct tm *p; \ -+ time(&t); \ -+ p = localtime(&t); \ -+ printf("[%d/%02d/%02d %02d:%02d:%02d][LOG:%s:%3d]"info"\n", \ -+ p->tm_year + 1900, p->tm_mon+1, p->tm_mday, \ -+ p->tm_hour, p->tm_min, p->tm_sec, __func__, __LINE__, ##__VA_ARGS__); \ -+ } while (0); -+ -+void rshim_close_all_fd() -+{ -+ DIR *dir = NULL; -+ struct dirent *entry; -+ dir = opendir("/proc/self/fd/"); -+ if (dir == NULL) { -+ rshim_err("open path:/proc/self/fd/ failed"); -+ return; -+ } -+ while (entry = readdir(dir)) { -+ int fd = atoi(entry->d_name); -+ if (fd <= 2) -+ continue; -+ close(fd); -+ } -+ closedir(dir); -+ return; -+} -+ -+int rshim_get_file_size(char *file) -+{ -+ int size = 0; -+ FILE *f = fopen(file, "rb"); -+ if (f == NULL) { -+ rshim_err("File:%s fopen failed.", file); -+ return -1; -+ } -+ fseek(f, 0, SEEK_END); -+ size = ftell(f); -+ fclose(f); -+ return size; -+} -+ -+void rshim_reg_file_open(int fd_target, char *path, int perm, int offset) -+{ -+ int fd = open(path, perm); -+ int fd2 = -1; -+ if (fd < 0) { -+ rshim_err("Open file:%s failed, fd:%d err:%s", path, fd, strerror(errno)); -+ return; -+ } -+ if (fd != fd_target) { -+ fd2 = dup2(fd, fd_target); -+ if (fd2 != fd_target) { -+ rshim_err("Failed to open file:%s by fd:%d", path, fd_target); -+ close(fd2); -+ close(fd); -+ return; -+ } -+ close(fd); -+ } -+ int off = lseek(fd_target, offset, SEEK_SET); -+ if (off < 0) { -+ rshim_err("Failed to set offset:%d to file:%s, fd:%d, fd2:%d", offset, path, fd, fd2); -+ return; -+ } -+ rshim_log("Successed to set offset:%d to file:%s, fd:%d, fd2:%d", offset, path, fd, fd2); -+ return; -+} -+ -+void rshim_reg_file_resume(const char * const json_buf) -+{ -+ const cJSON *files; -+ const cJSON *file; -+ const cJSON *fd; -+ const cJSON *path; -+ const cJSON *perm; -+ const cJSON *offset; -+ int curfd = 3; // begin from 3 -+ cJSON *fd_json = cJSON_Parse(json_buf); -+ if (fd_json == NULL) -+ { -+ const char *error_ptr = cJSON_GetErrorPtr(); -+ if (error_ptr != NULL) -+ fprintf(stderr, "Error before: %s\n", error_ptr); -+ goto end; -+ } -+ files = cJSON_GetObjectItemCaseSensitive(fd_json, "Files"); -+ cJSON_ArrayForEach(file, files) { -+ fd = cJSON_GetObjectItemCaseSensitive(file, "Fd"); -+ path = cJSON_GetObjectItemCaseSensitive(file, "Path"); -+ perm = cJSON_GetObjectItemCaseSensitive(file, "Perm"); -+ offset = cJSON_GetObjectItemCaseSensitive(file, "Offset"); -+ rshim_log("Get file from json fd:%d path:%s perm:%d offset:%d", -+ fd->valueint, path->valuestring, perm->valueint, offset->valueint); -+ rshim_reg_file_open(fd->valueint, path->valuestring, perm->valueint, offset->valueint); -+ } -+ -+end: -+ cJSON_Delete(fd_json); -+ return; -+} -+ -+void rshim_reg_file_sync(char *json_file) -+{ -+#define RSHIM_JSON_SIZE_MAX 1024*1024*1024 // 限制为1M足够了 -+ rshim_close_all_fd(); -+ if (json_file == NULL) -+ return; -+ -+ int json_size = rshim_get_file_size(json_file); -+ if (json_size < 0 || json_size > RSHIM_JSON_SIZE_MAX) { -+ rshim_err("Get json file:%s size failed, size:%d.", json_file, json_size); -+ return; -+ } -+ rshim_log("Get json file:%s size:%d", json_file, json_size); -+ -+ char *json_buf = (char *)malloc(json_size + 1); -+ int json_len = 0; -+ if (json_buf == NULL) { -+ rshim_err("Malloc error."); -+ return; -+ } -+ memset(json_buf, 0, json_size + 1); -+ int json_fd = open(json_file, O_RDONLY); -+ if (json_fd < 0) { -+ rshim_err("Open json file:%s failed, err:%s", json_file, strerror(errno)); -+ goto end; -+ } -+ json_len = read(json_fd, json_buf, json_size + 1); -+ if (json_len <= 0) { -+ rshim_err("Failed to read from json file:%s, ret:%d err:%s", json_file, json_len, strerror(errno)); -+ close(json_fd); -+ goto end; -+ } -+ close(json_fd); -+ remove(json_file); -+ rshim_reg_file_resume((const char * const)json_buf); -+end: -+ free(json_buf); -+ return; -+} -+ -+/* -+ param list: -+ 1) -f xxx.json binary param1 param2 ... -+ 2) binary param1 param2... -+*/ -+int main(int argc, char *argv[]) -+{ -+ char *json_file = NULL; -+ char **newarg = NULL; -+ -+ // 至少得有需要执行的二进制名称 -+ if (argc < 2 || (strcmp(argv[1], "-f") == 0 && argc < 4)) { -+ rshim_err("Input argument list too short."); -+ return -1; -+ } -+ -+ if (strcmp(argv[1], "-f") == 0) { -+ json_file = argv[2]; -+ newarg = &argv[3]; -+ } else { -+ newarg = &argv[1]; -+ } -+ -+ rshim_reg_file_sync(json_file); -+ execvp(newarg[0], newarg); -+ perror("execve failed."); -+ -+ exit(EXIT_FAILURE); -+} -+ -diff --git a/qtfs/rexec/server.go b/qtfs/rexec/server.go -index de3f6cf..32a91de 100644 ---- a/qtfs/rexec/server.go -+++ b/qtfs/rexec/server.go -@@ -128,7 +128,16 @@ func main() { - } - return - } -- cmd := exec.Command(command.Cmd, command.Args...) -+ -+ args := []string{} -+ fdFilePath := restoreFileInfo(command.Cmd, command.Files) -+ if fdFilePath != "" { -+ args = append(args, "-f", fdFilePath) -+ } -+ args = append(args, command.Cmd) -+ args = append(args, command.Args...) -+ -+ cmd := exec.Command("/usr/bin/rexec_shim", args...) - cmd.Stdout = command.Stdout - cmd.Stderr = command.Stderr - cmd.Env = append([]string{}, command.Env...) --- -2.33.0 - diff --git a/0009-Keep-doc-same-with-docs-in-openEuler.patch b/0009-Keep-doc-same-with-docs-in-openEuler.patch new file mode 100644 index 0000000000000000000000000000000000000000..d7ae771f1db0db0826b0c6619fc0176d18fc2a26 --- /dev/null +++ b/0009-Keep-doc-same-with-docs-in-openEuler.patch @@ -0,0 +1,325 @@ +From 67b7259d810c9e07227e7a1475acdc1141e4424e Mon Sep 17 00:00:00 2001 +From: Weifeng Su +Date: Thu, 8 Jun 2023 14:17:00 +0000 +Subject: Keep doc same with docs in openEuler + +Signed-off-by: Weifeng Su +--- + qtfs/doc/overview.md | 11 ++ + ...77\347\224\250\346\211\213\345\206\214.md" | 69 ++++++++ + ...40\346\204\237\345\215\270\350\275\275.md" | 31 ++++ + ...50\347\275\262\346\214\207\345\257\274.md" | 166 ++++++++++++++++++ + 7 files changed, 277 insertions(+) + create mode 100644 qtfs/doc/overview.md + create mode 100644 "qtfs/doc/qtfs\345\205\261\344\272\253\346\226\207\344\273\266\347\263\273\347\273\237\346\236\266\346\236\204\345\217\212\344\275\277\347\224\250\346\211\213\345\206\214.md" + create mode 100644 "qtfs/doc/\345\256\271\345\231\250\347\256\241\347\220\206\351\235\242\346\227\240\346\204\237\345\215\270\350\275\275.md" + create mode 100644 "qtfs/doc/\346\227\240\346\204\237\345\215\270\350\275\275\351\203\250\347\275\262\346\214\207\345\257\274.md" + +diff --git a/qtfs/doc/overview.md b/qtfs/doc/overview.md +new file mode 100644 +index 0000000..518deb0 +--- /dev/null ++++ b/qtfs/doc/overview.md +@@ -0,0 +1,11 @@ ++# 容器管理面DPU无感卸载指南 ++ ++本文档介绍基于openEuler操作系统的容器管理面DPU无感卸载功能特性及安装部署方法,该特性可以通过操作系统提供的统一抽象层,屏蔽容器管理面跨主机资源访问的差异,实现容器管理面业务无感卸载到DPU上。 ++ ++本文档适用于使用openEuler系统并希望了解和使用操作系统内核及容器的社区开发者、开源爱好者以及相关合作伙伴。使用人员需要具备以下经验和技能: ++ ++- 熟悉Linux基本操作 ++ ++- 熟悉linux内核文件系统相关基础机制 ++ ++- 对kubernetes和docker有一定了解,熟悉docker及kubernetes部署及使用 +\ No newline at end of file + +diff --git "a/qtfs/doc/qtfs\345\205\261\344\272\253\346\226\207\344\273\266\347\263\273\347\273\237\346\236\266\346\236\204\345\217\212\344\275\277\347\224\250\346\211\213\345\206\214.md" "b/qtfs/doc/qtfs\345\205\261\344\272\253\346\226\207\344\273\266\347\263\273\347\273\237\346\236\266\346\236\204\345\217\212\344\275\277\347\224\250\346\211\213\345\206\214.md" +new file mode 100644 +index 0000000..8088f48 +--- /dev/null ++++ "b/qtfs/doc/qtfs\345\205\261\344\272\253\346\226\207\344\273\266\347\263\273\347\273\237\346\236\266\346\236\204\345\217\212\344\275\277\347\224\250\346\211\213\345\206\214.md" +@@ -0,0 +1,69 @@ ++# qtfs ++ ++## 介绍 ++ ++qtfs是一个共享文件系统项目,可部署在host-dpu的硬件架构上,也可以部署在2台服务器之间。以客户端服务器的模式工作,使客户端能通过qtfs访问服务端的指定文件系统,得到本地文件访问一致的体验。 ++ ++qtfs的特性: ++ +++ 支持挂载点传播; ++ +++ 支持proc、sys、cgroup等特殊文件系统的共享; ++ +++ 支持远程文件读写的共享; ++ +++ 支持在客户端对服务端的文件系统进行远程挂载; ++ +++ 支持特殊文件的定制化处理; ++ +++ 支持远端fifo、unix-socket等,并且支持epoll,使客户端和服务端像本地通信一样使用这些文件; ++ +++ 支持基于host-dpu架构通过PCIe协议底层通信,性能大大优于网络; ++ +++ 支持内核模块形式开发,无需对内核进行侵入式修改。 ++ ++## 软件架构 ++ ++软件大体框架图: ++ ++![qtfs-arch](./figures/qtfs-arch.png) ++ ++## 安装教程 ++ ++目录说明: ++ +++ **qtfs**: 客户端内核模块相关代码,直接在该目录下编译客户端ko。 ++ +++ **qtfs_server**: 服务端内核模块相关代码,直接在该目录下编译服务端ko和相关程序。 ++ +++ **qtinfo**: 诊断工具,支持查询文件系统的工作状态以及修改log级别等。 ++ +++ **demo**、**test**、**doc**: 测试程序、演示程序以及项目资料等。 ++ +++ 根目录: 客户端与服务端通用的公共模块代码。 ++ ++首先找两台服务器(或虚拟机)配置内核编译环境: ++ ++ 1. 要求内核版本在5.10或更高版本。 ++  2. 安装内核开发包:yum install kernel-devel。 ++ ++服务端安装: ++ ++ 1. cd qtfs_server ++ 2. make clean && make ++ 3. insmod qtfs_server.ko qtfs_server_ip=x.x.x.x qtfs_server_port=12345 qtfs_log_level=WARN ++ 4. ./engine 4096 16 ++ ++客户端安装: ++ ++ 1. cd qtfs ++ 2. make clean && make ++ 3. insmod qtfs.ko qtfs_server_ip=x.x.x.x qtfs_server_port=12345 qtfs_log_level=WARN ++ ++## 使用说明 ++ ++安装完成后,客户端通过挂载把服务端的文件系统让客户端可见,例如: ++ ++ mount -t qtfs / /root/mnt/ ++ ++客户端进入"/root/mnt"后便可查看到server端的所有文件,以及对其进行相关操作。 +diff --git "a/qtfs/doc/\345\256\271\345\231\250\347\256\241\347\220\206\351\235\242\346\227\240\346\204\237\345\215\270\350\275\275.md" "b/qtfs/doc/\345\256\271\345\231\250\347\256\241\347\220\206\351\235\242\346\227\240\346\204\237\345\215\270\350\275\275.md" +new file mode 100644 +index 0000000..2e4be2f +--- /dev/null ++++ "b/qtfs/doc/\345\256\271\345\231\250\347\256\241\347\220\206\351\235\242\346\227\240\346\204\237\345\215\270\350\275\275.md" +@@ -0,0 +1,31 @@ ++# 容器管理面无感卸载介绍 ++ ++## 概述 ++ ++在数据中心及云场景下,随着摩尔定律失效,通用处理单元CPU算力增长速率放缓,而同时网络IO类速率及性能不断攀升,二者增长速率差异形成的剪刀差,即当前通用处理器的处理能力无法跟上网络、磁盘等IO处理的需求。传统数据中心下越来越多的通用CPU算力被IO及管理面等占用,这部分资源损耗称之为数据中心税(Data-center Tax)。据AWS统计,数据中心税可能占据数据中心算力的30%以上,部分场景下甚至可能更多。 ++ ++DPU的出现就是为了将这部分算力资源从主机CPU上解放出来,通过将管理面、网络、存储、安全等能力卸载到专有的处理器芯片(DPU)上进行处理加速,达成降本增效的结果。目前主流云厂商如AWS、阿里云、华为云都通过自研芯片完成管理面及相关数据面的卸载,达成数据中心计算资源100%售卖给客户。 ++ ++管理面进程卸载到DPU可以通过对组件源码进行拆分达成,将源码根据功能逻辑拆分成独立运行的两部分,分别运行在主机和DPU,达成组件卸载的目的。但是这种做法有以下问题:一是影响组件的软件兼容性,组件后续版本升级和维护需要自己维护相关patch,带来一定的维护工作量;二是卸载工作无法被其他组件继承,后续组件卸载后仍需要进行代码逻辑分析和拆分等工作。为解决上述问题,本方案提出DPU的无感卸载,通过OS提供的抽象层,屏蔽应用在主机和DPU间跨主机访问的差异,让业务进程近似0改动达成卸载到DPU运行的目标,且这部分工作属于操作系统通用层,与上层业务无关,其他业务进行DPU卸载时也可以继承。 ++ ++## 架构介绍 ++ ++#### 容器管理面DPU无感卸载架构 ++ ++**图1**容器管理面DPU无感卸载架构 ++ ++![offload-arch](./figures/offload-arch.png) ++ ++如图1所示,容器管理面卸载后,dockerd、kubelet等管理进程运行在DPU侧,容器进程本身运行在HOST,进程之间的交互关系由系统层提供对应的能力来保证: ++ ++* 通信层:DPU和主机之间可能通过PCIe或网络进行通信,需要基于底层物理连接提供通信接口层,为上层业务提供通信接口。 ++ ++* 内核共享文件系统qtfs:容器管理面组件kubelet、dockerd与容器进程之间的主要交互通过文件系统进行;管理面工具需要为容器进程准备rootfs、volume等数据面路径;还需要在运行时通过proc文件系统、cgroup文件系统等控制和监控容器进程的资源及状态。共享文件系统的详细介绍参考[共享文件系统介绍](qtfs共享文件系统架构及使用手册.md) ++ ++* 用户态卸载环境:用户态需要使用qtfs为容器管理面准备卸载后的运行时环境,将主机的容器管理及运行时相关目录远程挂载到DPU;另外由于需要挂载proc、sys、cgroup等系统管理文件系统,为防止对DPU原生系统功能的破坏,上述挂载动作都在chroot环境内完成。另外管理面(运行于DPU)和容器进程(运行于主机)之间仍存在调用关系,需要通过远程二进制执行工具(rexec)提供对应功能。 ++ ++容器管理面无感卸载的操作步骤可参考[部署指导文档](./无感卸载部署指导.md) ++ ++> ![](./public_sys-resources/icon-note.gif)**说明**: ++> ++> 上述操作指导涉及对容器管理面组件的少量改动和rexec工具修改,这些修改基于指定版本,其他版本可基于实际执行环境做适配修改。文档中提供的patch仅供验证指导使用,不具备实际商用的条件 +\ No newline at end of file +diff --git "a/qtfs/doc/\346\227\240\346\204\237\345\215\270\350\275\275\351\203\250\347\275\262\346\214\207\345\257\274.md" "b/qtfs/doc/\346\227\240\346\204\237\345\215\270\350\275\275\351\203\250\347\275\262\346\214\207\345\257\274.md" +new file mode 100644 +index 0000000..c15eed9 +--- /dev/null ++++ "b/qtfs/doc/\346\227\240\346\204\237\345\215\270\350\275\275\351\203\250\347\275\262\346\214\207\345\257\274.md" +@@ -0,0 +1,166 @@ ++ ++# 容器管理面无感卸载部署指导 ++ ++> ![](./public_sys-resources/icon-note.gif)**说明**: ++> ++> 本指导涉及对容器管理面组件的少量改动和rexec工具修改,这些修改基于指定版本,其他版本可基于实际执行环境做适配修改。文档中提供的patch仅供验证指导使用,不具备实际商用的条件。 ++ ++> ![](./public_sys-resources/icon-note.gif)**说明**: ++> ++> 当前共享文件系统之间通信通过网络完成,可通过网络互连的两台物理机器或VM模拟验证。 ++> ++> 建议用户验证前先搭建可正常使用的kubernetes集群和容器运行环境,针对其中单个节点的管理面进程进行卸载验证,卸载环境(DPU)可选择一台具备网络连接的物理机或VM。 ++ ++## 简介 ++ ++容器管理面,即kubernetes、dockerd、containerd、isulad等容器的管理工具,而容器管理面卸载,即是将容器管理面卸载到与容器所在机器(以下称为HOST)之外的另一台机器(当前场景下是指DPU,一个具备独立运行环境的硬件集合)上运行。 ++ ++我们使用共享文件系统qtfs将HOST上与容器运行相关的目录挂载到DPU上,使得容器管理面工具(运行在DPU)可以访问到这些目录,并为容器(运行在HOST)准备运行所需要的环境,此处,因为需要挂载远端的proc和sys等特殊文件系统,所以,我们创建了一个专门的rootfs以作为kubernetes、dockerd的运行环境(以下称为`/another_rootfs`)。 ++ ++并且通过rexec执行容器的拉起、删除等操作,使得可以将容器管理面和容器分离在不同的两台机器上,远程对容器进行管理。 ++ ++## 相关组件补丁介绍 ++ ++#### rexec介绍 ++ ++rexec是一个用go语言开发的远程执行工具,基于docker/libchan下的[rexec](https://github.com/docker/libchan/tree/master/examples/rexec)示例工具改造而成,实现远程调用远端二进制的功能,为方便使用在rexec中增加了环境变量传递和监控原进程退出等能力。 ++ ++rexec工具的具体使用方式为在服务器端用`CMD_NET_ADDR=tcp://0.0.0.0:<端口号> rexec_server`的方式拉起rexec服务进程,然后在客户端用`CMD_NET_ADDR=tcp://<服务端ip>:<端口号> rexec [要执行的指令] `的方式启动,便可以调用rexec_server执行需要执行的指令,并等待指令执行结果返回。 ++ ++#### dockerd相关改动介绍 ++ ++对dockerd的改动基于18.09版本。 ++ ++在containerd中,暂时注释掉了通过hook调用libnetwork-setkey的部分,此处不影响容器的拉起。并且,为了docker load的正常使用,注释掉了在mounter_linux.go 中mount函数中一处错误的返回。 ++ ++最后,因为在容器管理面的运行环境中,将`/proc`挂在了服务端的proc文件系统,而本地的proc文件系统则挂载在了`/local_proc`,所以,dockerd以及containerd中的对`/proc/self/xxx`或者`/proc/getpid()/xxx`或者相关的文件系统访问的部分,我们统统将`/proc`改为了`/local_proc`。 ++ ++#### containerd相关改动介绍 ++ ++对于containerd的改动基于containerd-1.2-rc.1版本。 ++ ++在获取mountinfo时,因为`/proc/self/mountinfo`只能获取到dockerd本身在本地的mountinfo,而无法获取到服务端的mountinfo,所以,将其改为了`/proc/1/mountinfo`,使其通过获取服务端1号进程mountinfo的方式得到服务端的mountinfo。 ++ ++在contaienrd-shim中,将与containerd通信的unix socket改为了用tcp通信,containerd通过`SHIM_HOST`环境变量获取containerd-shim所运行环境的ip,即服务端ip。用shim的哈希值计算出一个端口号,并以此作为通信的端口,来拉起containerd-shim. ++ ++并且,将原来的通过系统调用给contaienr-shim发信号的方式,改为了通过远程调用kill指令的方式向shim发信号,确保了docker杀死容器的行为可以正确的执行。 ++ ++#### kubernetes相关改动介绍 ++ ++kubelet暂不需要功能性改动,可能会遇到容器QoS管理器首次设置失败的错误,该错误不影响后续Pods拉起流程,暂时忽略该报错。 ++ ++## 容器管理面卸载操作指南 ++ ++在服务器端和客户端,都要拉起rexec_server。服务器端拉起rexec_server,主要是用于客户端创建容器时用rexec拉起containerd-shim,而客户端拉起rexec_server,则是为了执行containerd-shim对dockerd和containerd的调用。 ++ ++#### 服务器端 ++ ++创建容器管理面所需要的文件夹,然后插入qtfs_server.ko,并拉起engine进程。 ++ ++此外在服务器端,还需要创建rexec脚本/usr/bin/dockerd. ++ ++``` shell ++#!/bin/bash ++CMD_NET_ADDR=tcp://<客户端ip>: rexec /usr/bin/dockerd $* ++``` ++ ++#### 客户端 ++ ++需要准备一个rootfs,作为dockerd与containerd的运行环境,通过如下的脚本,将dockerd、containerd所需要的服务端目录挂载到客户端。并且,需要确保在以下脚本中被挂载的远程目录在服务端和客户端都存在。 ++ ++``` shell ++#!/bin/bash ++mkdir -p /another_rootfs/var/run/docker/containerd ++iptables -t nat -N DOCKER ++echo "---------insmod qtfs ko----------" ++insmod /YOUR/QTFS/PATH/qtfs.ko qtfs_server_ip=<服务端ip> qtfs_log_level=INFO ++ ++# chroot环境内的proc使用DPU的proc共享文件系统替换,需要将本机真实proc文件系统挂载到local_proc下使用 ++mount -t proc proc /another_rootfs/local_proc/ ++ ++# 将chroot内环境与外部环境bind,方便进行配置和运行 ++mount --bind /var/run/ /another_rootfs/var/run/ ++mount --bind /var/lib/ /another_rootfs/var/lib/ ++mount --bind /etc /another_rootfs/etc ++ ++mkdir -p /another_rootfs/var/lib/isulad ++ ++# 在chroot环境内创建并挂载dev、sys和cgroup文件系统 ++mount -t devtmpfs devtmpfs /another_rootfs/dev/ ++mount -t sysfs sysfs /another_rootfs/sys ++mkdir -p /another_rootfs/sys/fs/cgroup ++mount -t tmpfs tmpfs /another_rootfs/sys/fs/cgroup ++list="perf_event freezer files net_cls,net_prio hugetlb pids rdma cpu,cpuacct memory devices blkio cpuset" ++for i in $list ++do ++ echo $i ++ mkdir -p /another_rootfs/sys/fs/cgroup/$i ++ mount -t cgroup cgroup -o rw,nosuid,nodev,noexec,relatime,$i /another_rootfs/sys/fs/cgroup/$i ++done ++ ++## common system dir ++mount -t qtfs -o proc /proc /another_rootfs/proc ++echo "proc" ++mount -t qtfs /sys /another_rootfs/sys ++echo "cgroup" ++ ++# 挂载容器管理面所需要的共享目录 ++mount -t qtfs /var/lib/docker/containers /another_rootfs/var/lib/docker/containers ++mount -t qtfs /var/lib/docker/containerd /another_rootfs/var/lib/docker/containerd ++mount -t qtfs /var/lib/docker/overlay2 /another_rootfs/var/lib/docker/overlay2 ++mount -t qtfs /var/lib/docker/image /another_rootfs/var/lib/docker/image ++mount -t qtfs /var/lib/docker/tmp /another_rootfs/var/lib/docker/tmp ++mkdir -p /another_rootfs/run/containerd/io.containerd.runtime.v1.linux/ ++mount -t qtfs /run/containerd/io.containerd.runtime.v1.linux/ /another_rootfs/run/containerd/io.containerd.runtime.v1.linux/ ++mkdir -p /another_rootfs/var/run/docker/containerd ++mount -t qtfs /var/run/docker/containerd /another_rootfs/var/run/docker/containerd ++mount -t qtfs /var/lib/kubelet/pods /another_rootfs/var/lib/kubelet/pods ++``` ++ ++在/another_rootfs中,需要创建以下脚本,用来支持部分跨主机操作。 ++ ++* /another_rootfs/usr/local/bin/containerd-shim ++ ++``` shell ++#!/bin/bash ++CMD_NET_ADDR=tcp://<服务端ip>: /usr/bin/rexec /usr/bin/containerd-shim $* ++``` ++ ++* /another_rootfs/usr/local/bin/remote_kill ++ ++``` shell ++#!/bin/bash ++CMD_NET_ADDR=tcp://<服务端ip>: /usr/bin/rexec /usr/bin/kill $* ++``` ++ ++* /another_rootfs/usr/sbin/modprobe ++``` shell ++#!/bin/bash ++CMD_NET_ADDR=tcp://<服务端ip>: /usr/bin/rexec /usr/sbin/modprobe $* ++``` ++ ++在chroot到dockerd和containerd运行所需的rootfs后,用如下的命令拉起dockerd和containerd ++ ++* containerd ++``` shell ++#!/bin/bash ++SHIM_HOST=<服务端ip> containerd --config /var/run/docker/containerd/containerd.toml --address /var/run/containerd/containerd.sock ++``` ++ ++* dockerd ++``` shell ++#!/bin/bash ++SHIM_HOST=<服务端ip> CMD_NET_ADDR=tcp://<服务端ip>: /usr/bin/dockerd --containerd /var/run/containerd/containerd.sock ++``` ++ ++* kubelet ++ ++在chroot环境内使用原参数拉起kubelet即可。 ++ ++因为我们已经将/var/run/和/another_rootfs/var/run/绑定在了一起,所以可以在正常的rootfs下,通过docker来访问docker.sock接口进行容器管理。 ++ ++至此,完成容器管理面卸载到DPU,可以通过docker相关操作进行容器创建、删除等操作,也可以通过kubectl在当前节点进行pods调度和销毁,且实际容器业务进程运行在HOST侧。 ++ ++> ![](./public_sys-resources/icon-note.gif)**说明**: ++> ++> 本指导所述操作只涉及容器管理面进程卸载,不包含容器网络和数据卷volume等卸载,如有相关需求,需要通过额外的网络或存储卸载能力支持。本指导支持不带网络和存储的容器跨节点拉起。 +\ No newline at end of file +-- +2.33.0 + diff --git a/0010-Adapt-to-kernel-6.1-file-system-interface-changes.patch b/0010-Adapt-to-kernel-6.1-file-system-interface-changes.patch deleted file mode 100644 index b610481995270599cf825411e10ad4f243c21032..0000000000000000000000000000000000000000 --- a/0010-Adapt-to-kernel-6.1-file-system-interface-changes.patch +++ /dev/null @@ -1,344 +0,0 @@ -From e9f4fc2f658958a37f859a37084560c592c162ec Mon Sep 17 00:00:00 2001 -From: YangXin <245051644@qq.com> -Date: Fri, 10 Feb 2023 13:55:57 +0000 -Subject: [PATCH] Adapt to kernel 6.1 file system interface changes. - -Signed-off-by: YangXin <245051644@qq.com> ---- - qtfs/qtfs/ops.h | 2 +- - qtfs/qtfs/proc.c | 6 +++--- - qtfs/qtfs/qtfs-mod.c | 5 +++-- - qtfs/qtfs/sb.c | 43 ++++++++++++++++++++++------------------ - qtfs/qtfs/xattr.c | 4 ++++ - qtfs/qtfs_server/fsops.c | 16 +++++++-------- - 6 files changed, 43 insertions(+), 33 deletions(-) - -diff --git a/qtfs/qtfs/ops.h b/qtfs/qtfs/ops.h -index 5cab367..a18f4da 100644 ---- a/qtfs/qtfs/ops.h -+++ b/qtfs/qtfs/ops.h -@@ -15,7 +15,7 @@ bool is_sb_proc(struct super_block *sb); - struct inode *qtfs_iget(struct super_block *sb, struct inode_info *ii); - const char *qtfs_getlink(struct dentry *dentry, - struct inode *inode, struct delayed_call *done); --int qtfs_getattr(const struct path *, struct kstat *, u32, unsigned int); -+int qtfs_getattr(struct user_namespace *mnt_userns, const struct path *, struct kstat *, u32, unsigned int); - struct dentry * qtfs_lookup(struct inode *, struct dentry *, unsigned int); - - #endif -diff --git a/qtfs/qtfs/proc.c b/qtfs/qtfs/proc.c -index 60401d9..e37303e 100644 ---- a/qtfs/qtfs/proc.c -+++ b/qtfs/qtfs/proc.c -@@ -9,7 +9,7 @@ - - struct dentry *qtfs_proc_lookup(struct inode *parent_inode, struct dentry *child_dentry, unsigned int flags); - const char *qtfs_proc_getlink(struct dentry *dentry, struct inode *inode, struct delayed_call *done); --int qtfs_proc_getattr(const struct path *path, struct kstat *stat, u32 req_mask, unsigned int flags); -+int qtfs_proc_getattr(struct user_namespace *mnt_userns, const struct path *path, struct kstat *stat, u32 req_mask, unsigned int flags); - - enum qtfs_type qtfs_get_type(char *str) - { -@@ -187,7 +187,7 @@ remote: - return qtfs_getlink(dentry, inode, done); - } - --int qtfs_proc_getattr(const struct path *path, struct kstat *stat, u32 req_mask, unsigned int flags) -+int qtfs_proc_getattr(struct user_namespace *mnt_userns, const struct path *path, struct kstat *stat, u32 req_mask, unsigned int flags) - { - char cpath[NAME_MAX] = {0}; - char tmp[NAME_MAX] = {0}; -@@ -223,5 +223,5 @@ int qtfs_proc_getattr(const struct path *path, struct kstat *stat, u32 req_mask, - } - - remote: -- return qtfs_getattr(path, stat, req_mask, flags); -+ return qtfs_getattr(NULL, path, stat, req_mask, flags); - } -diff --git a/qtfs/qtfs/qtfs-mod.c b/qtfs/qtfs/qtfs-mod.c -index abd9443..eb8d21a 100644 ---- a/qtfs/qtfs/qtfs-mod.c -+++ b/qtfs/qtfs/qtfs-mod.c -@@ -1,5 +1,6 @@ - // SPDX-License-Identifier: GPL-2.0 - #include -+#include - #include "conn.h" - - #include "qtfs-mod.h" -@@ -114,7 +115,7 @@ connecting: - msleep(500); - } - if (pvar == NULL) { -- do_exit(0); -+ return 0; - } - qtfs_info("qtfs epoll thread establish a new connection."); - req = qtfs_sock_msg_buf(pvar, QTFS_RECV); -@@ -170,7 +171,7 @@ connecting: - qtfs_err("conn send failed, ret:%d\n", ret); - } - qtfs_epoll_cut_conn(pvar); -- do_exit(0); -+ return 0; - } - - struct file_operations qtfs_misc_fops = { -diff --git a/qtfs/qtfs/sb.c b/qtfs/qtfs/sb.c -index 104d137..38cac43 100644 ---- a/qtfs/qtfs/sb.c -+++ b/qtfs/qtfs/sb.c -@@ -461,13 +461,12 @@ static vm_fault_t qtfs_vm_fault(struct vm_fault *vmf) - return ret; - } - --static void qtfs_map_pages(struct vm_fault *vmf, -+static vm_fault_t qtfs_map_pages(struct vm_fault *vmf, - pgoff_t start_pgoff, pgoff_t end_pgoff) - { - qtfs_info("qtfs map pages enter, pgoff:%lu start:%lu end:%lu.", vmf->pgoff, start_pgoff, end_pgoff); - -- filemap_map_pages(vmf, start_pgoff, end_pgoff); -- return; -+ return filemap_map_pages(vmf, start_pgoff, end_pgoff); - } - - static vm_fault_t qtfs_page_mkwrite(struct vm_fault *vmf) -@@ -665,7 +664,6 @@ static struct file_operations qtfs_file_ops = { - .poll = qtfsfifo_poll, - }; - -- - static int qtfs_readpage(struct file *file, struct page *page) - { - void *kaddr = NULL; -@@ -682,6 +680,14 @@ static int qtfs_readpage(struct file *file, struct page *page) - return 0; - } - -+static int qtfs_read_folio(struct file *file, struct folio *folio) -+{ -+ struct page *page = &folio->page; -+ qtfs_readpage(file, page); -+ -+ return 0; -+} -+ - static struct page **qtfs_alloc_pages(unsigned int nr) - { - struct page **pages = kzalloc(nr * (sizeof(struct page *)), GFP_KERNEL); -@@ -726,19 +732,18 @@ static int qtfs_writepages(struct address_space *mapping, - return 0; - } - --static int qtfs_setpagedirty(struct page *page) -+static bool qtfs_dirty_folio(struct address_space *mapping, struct folio *folio) - { - qtfs_info("qtfs set page dirty."); -- __set_page_dirty_nobuffers(page); -- return 0; -+ return filemap_dirty_folio(mapping, folio); - } - - static const struct address_space_operations qtfs_aops = { -- .readpage = qtfs_readpage, -+ .read_folio = qtfs_read_folio, - .readahead = qtfs_readahead, - .writepage = qtfs_writepage, - .writepages = qtfs_writepages, -- .set_page_dirty = qtfs_setpagedirty, -+ .dirty_folio = qtfs_dirty_folio, - }; - - int qtfs_new_entry(struct inode *inode, struct dentry *dentry) -@@ -758,7 +763,7 @@ int qtfs_new_entry(struct inode *inode, struct dentry *dentry) - return 0; - } - --int qtfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) -+int qtfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir, struct dentry *dentry, umode_t mode) - { - struct qtfs_sock_var_s *pvar = qtfs_conn_get_param(); - struct qtreq_mkdir *req = NULL; -@@ -793,7 +798,7 @@ int qtfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) - return ret; - } - --int qtfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl) -+int qtfs_create(struct user_namespace *mnt_userns, struct inode *dir, struct dentry *dentry, umode_t mode, bool excl) - { - struct qtfs_sock_var_s *pvar = qtfs_conn_get_param(); - struct qtreq_icreate *req; -@@ -833,7 +838,7 @@ int qtfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool exc - return ret ? ret : ret2; - } - --int qtfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) -+int qtfs_mknod(struct user_namespace *mnt_userns, struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) - { - struct qtfs_sock_var_s *pvar = qtfs_conn_get_param(); - struct qtreq_mknod *req; -@@ -1093,7 +1098,7 @@ err_end: - return error; - } - --int qtfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) -+int qtfs_symlink(struct user_namespace *mnt_userns, struct inode *dir, struct dentry *dentry, const char *symname) - { - struct qtfs_sock_var_s *pvar = qtfs_conn_get_param(); - struct qtreq_symlink *req; -@@ -1138,7 +1143,7 @@ err_end: - return error; - } - --int qtfs_getattr(const struct path *path, struct kstat *stat, u32 req_mask, unsigned int flags) -+int qtfs_getattr(struct user_namespace *mnt_userns, const struct path *path, struct kstat *stat, u32 req_mask, unsigned int flags) - { - struct qtfs_sock_var_s *pvar = qtfs_conn_get_param(); - struct qtreq_getattr *req; -@@ -1182,7 +1187,7 @@ int qtfs_getattr(const struct path *path, struct kstat *stat, u32 req_mask, unsi - return 0; - } - --int qtfs_setattr(struct dentry *dentry, struct iattr *attr) -+int qtfs_setattr(struct user_namespace *mnt_userns, struct dentry *dentry, struct iattr *attr) - { - struct qtfs_sock_var_s *pvar = qtfs_conn_get_param(); - struct qtreq_setattr *req; -@@ -1277,9 +1282,9 @@ const char *qtfs_getlink(struct dentry *dentry, - return link; - } - --int qtfs_rename(struct inode *old_dir, struct dentry *old_dentry, -- struct inode *new_dir, struct dentry *new_dentry, -- unsigned int flags) -+int qtfs_rename(struct user_namespace *mnt_userns, struct inode *old_dir, -+ struct dentry *old_dentry, struct inode *new_dir, -+ struct dentry *new_dentry, unsigned int flags) - { - struct qtreq_rename *req; - struct qtrsp_rename *rsp; -@@ -1364,7 +1369,7 @@ static int qtfs_fill_super(struct super_block *sb, void *priv_data, int silent) - root_inode = new_inode(sb); - root_inode->i_ino = 1; - -- inode_init_owner(root_inode, NULL, mode); -+ inode_init_owner(&init_user_ns, root_inode, NULL, mode); - root_inode->i_sb = sb; - if (priv->type == QTFS_PROC) { - qtfs_info("qtfs type: proc\n"); -diff --git a/qtfs/qtfs/xattr.c b/qtfs/qtfs/xattr.c -index a2a605d..61153c0 100644 ---- a/qtfs/qtfs/xattr.c -+++ b/qtfs/qtfs/xattr.c -@@ -59,6 +59,7 @@ static int qtfs_xattr_set(const struct xattr_handler *handler, - - static int - qtfs_xattr_user_set(const struct xattr_handler *handler, -+ struct user_namespace *mnt_userns, - struct dentry *unused, struct inode *inode, - const char *name, const void *value, - size_t size, int flags) -@@ -69,6 +70,7 @@ qtfs_xattr_user_set(const struct xattr_handler *handler, - - static int - qtfs_xattr_trusted_set(const struct xattr_handler *handler, -+ struct user_namespace *mnt_userns, - struct dentry *unused, struct inode *inode, - const char *name, const void *value, - size_t size, int flags) -@@ -78,6 +80,7 @@ qtfs_xattr_trusted_set(const struct xattr_handler *handler, - - static int - qtfs_xattr_security_set(const struct xattr_handler *handler, -+ struct user_namespace *mnt_userns, - struct dentry *unused, struct inode *inode, - const char *name, const void *value, - size_t size, int flags) -@@ -87,6 +90,7 @@ qtfs_xattr_security_set(const struct xattr_handler *handler, - - static int - qtfs_xattr_hurd_set(const struct xattr_handler *handler, -+ struct user_namespace *mnt_userns, - struct dentry *unused, struct inode *inode, - const char *name, const void *value, - size_t size, int flags) -diff --git a/qtfs/qtfs_server/fsops.c b/qtfs/qtfs_server/fsops.c -index 6c3e201..87caf90 100644 ---- a/qtfs/qtfs_server/fsops.c -+++ b/qtfs/qtfs_server/fsops.c -@@ -431,7 +431,7 @@ static int handle_lookup(struct qtserver_arg *arg) - return sizeof(struct qtrsp_lookup); - } - --static int qtfs_filldir(struct dir_context *ctx, const char *name, int namelen, -+static bool qtfs_filldir(struct dir_context *ctx, const char *name, int namelen, - loff_t offset, u64 ino, unsigned int d_type) - { - struct qtfs_dirent64 *dirent, *prev; -@@ -440,7 +440,7 @@ static int qtfs_filldir(struct dir_context *ctx, const char *name, int namelen, - int prev_reclen; - - if (reclen > buf->count) -- return -EINVAL; -+ return false; - - prev_reclen = buf->prev_reclen; - dirent = buf->dir; -@@ -455,7 +455,7 @@ static int qtfs_filldir(struct dir_context *ctx, const char *name, int namelen, - buf->dir = (void *)dirent + reclen; - buf->count -= reclen; - buf->vldcnt++; -- return 0; -+ return true; - } - - static int handle_readdir(struct qtserver_arg *arg) -@@ -642,7 +642,7 @@ static int handle_setattr(struct qtserver_arg *arg) - } - - inode_lock(inode); -- rsp->errno = notify_change(path.dentry, &req->attr, NULL); -+ rsp->errno = notify_change(&init_user_ns, path.dentry, &req->attr, NULL); - if (rsp->errno < 0) { - rsp->ret = QTFS_ERR; - qtfs_err("handle setattr, path:<%s> failed with %d.\n", req->path, ret); -@@ -716,7 +716,7 @@ retry: - req->mode &= ~current_umask(); - error = security_path_mknod(&path, dent, req->mode, req->dev); - if (!error) -- error = vfs_mknod(path.dentry->d_inode, dent, req->mode, req->dev); -+ error = vfs_mknod(&init_user_ns, path.dentry->d_inode, dent, req->mode, req->dev); - done_path_create(&path, dent); - if (error == -ESTALE && !(flags & LOOKUP_REVAL)) { - flags |= LOOKUP_REVAL; -@@ -794,7 +794,7 @@ retry: - return sizeof(struct qtrsp_symlink); - } - -- rsp->errno = vfs_symlink(path.dentry->d_inode, dentry, oldname); -+ rsp->errno = vfs_symlink(&init_user_ns, path.dentry->d_inode, dentry, oldname); - done_path_create(&path, dentry); - if (rsp->errno == -ESTALE && !(lookup_flags & LOOKUP_REVAL)) { - lookup_flags |= LOOKUP_REVAL; -@@ -922,7 +922,7 @@ int handle_xattrset(struct qtserver_arg *arg) - goto err_handle; - } - -- rsp->errno = vfs_setxattr(path.dentry, &req->buf[req->d.pathlen], &req->buf[req->d.pathlen + req->d.namelen], req->d.size, req->d.flags); -+ rsp->errno = vfs_setxattr(&init_user_ns, path.dentry, &req->buf[req->d.pathlen], &req->buf[req->d.pathlen + req->d.namelen], req->d.size, req->d.flags); - qtfs_info("handle xattrset path:%s name:%s value:%s ret:%d size:%lu flags:%d", req->buf, - &req->buf[req->d.pathlen], &req->buf[req->d.pathlen + req->d.namelen], rsp->errno, - req->d.size, req->d.flags); -@@ -963,7 +963,7 @@ int handle_xattrget(struct qtserver_arg *arg) - } - } - -- error = vfs_getxattr(path.dentry, req->d.prefix_name, kvalue, req->d.size); -+ error = vfs_getxattr(&init_user_ns, path.dentry, req->d.prefix_name, kvalue, req->d.size); - path_put(&path); - if (error > 0) { - if (req->d.pos >= error) { --- -2.33.0 - diff --git a/0010-update-libvirt-doc.patch b/0010-update-libvirt-doc.patch new file mode 100644 index 0000000000000000000000000000000000000000..68f933b6529d6eda49ee4b121940eacd8825d9ba --- /dev/null +++ b/0010-update-libvirt-doc.patch @@ -0,0 +1,56 @@ +From ab96a3f0279f6befda7c66ea80956defe4b90f40 Mon Sep 17 00:00:00 2001 +From: liqiang +Date: Fri, 9 Jun 2023 15:20:31 +0800 +Subject: update libvirt doc + +Signed-off-by: liqiang +--- + ...\351\233\266\346\220\255\345\273\272v1.1.md" | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +diff --git "a/usecases/libvirtd-offload/libvirt\347\233\264\350\277\236\350\201\232\345\220\210\347\216\257\345\242\203\344\273\216\351\233\266\346\220\255\345\273\272v1.1.md" "b/usecases/libvirtd-offload/libvirt\347\233\264\350\277\236\350\201\232\345\220\210\347\216\257\345\242\203\344\273\216\351\233\266\346\220\255\345\273\272v1.1.md" +index c1f9c87..85541dc 100644 +--- "a/usecases/libvirtd-offload/libvirt\347\233\264\350\277\236\350\201\232\345\220\210\347\216\257\345\242\203\344\273\216\351\233\266\346\220\255\345\273\272v1.1.md" ++++ "b/usecases/libvirtd-offload/libvirt\347\233\264\350\277\236\350\201\232\345\220\210\347\216\257\345\242\203\344\273\216\351\233\266\346\220\255\345\273\272v1.1.md" +@@ -2,16 +2,27 @@ + | ---- | --------- | ---- | ------------------------------------------------------------ | + | V1.0 | 2022/12/5 | 李强 | 创建文档 | + | V1.1 | 2023/2/6 | 李强 | 增加uds proxy组件部署介绍;增加rexec组件部署介绍;修改libvirt相关描述,适配uds proxy组件。 | +-| V1.2 | 2023/3/22 | 李强 | rexec重构后,更新rexec组件部署说明。 | +-| V1.3 | 2023/3/27 | 李强 | qtfs为connect syscall适配uds做改动 | ++| V1.2 | 2023/3/22 | 李强 | rexec重构后,更新rexec组件部署说明。 | ++| V1.3 | 2023/3/27 | 李强 | qtfs为connect syscall适配uds做改动。 | ++| V1.4 | 2023/6/9 | 李强 | 将默认的组件链接方式改为vsock,网络改为测试模式。 | + + + # **1** 硬件准备 + ++## 测试模式 ++ + 需准备2台物理机(虚机当前未试过),网络互通。 + + 其中一台作为DPU模拟,另一台作为HOST模拟。在本文档中用DPU和HOST指代这两台服务器。 + ++注意:测试模式因为会暴露网络端口且不做连接认证,存在网络安全风险,仅能用于内部测试验证,不要用于实际生产环境。 ++ ++## vsock模式 ++ ++需要DPU加HOST,且DPU能支持通过virtio提供vsock通信方式。 ++ ++目前还未基于真实的支持DPU vsock的环境调试过,本文档当前仅描述基于测试模式的方法,下面的内容依然默认使用测试模式。 ++ + + # **2** libvirt卸载架构图 + +@@ -40,7 +51,7 @@ udsproxyd是一个跨主机的unix domain socket代理服务,需要分别部 + ```bash + cd qtfs/ipc + +-make && make install ++make -j UDS_TEST_MODE=1 && make install + ``` + + 当前最新版本下,qtfs server侧的engine服务已经整合了udsproxyd的能力,所以server侧若部署了qtfs后不需要再额外启动udsproxyd。client侧则单独拉起udsproxyd服务: +-- +2.33.0 + diff --git a/0011-ioctl-enhance-and-rewrite-duplicate-code.patch b/0011-ioctl-enhance-and-rewrite-duplicate-code.patch new file mode 100644 index 0000000000000000000000000000000000000000..c975b0cf184fe80507ef699abd7cea1004c6b317 --- /dev/null +++ b/0011-ioctl-enhance-and-rewrite-duplicate-code.patch @@ -0,0 +1,286 @@ +From bf30c2c3dc20b2b5e9562313a4c50541ebe313de Mon Sep 17 00:00:00 2001 +From: liqiang +Date: Sat, 10 Jun 2023 11:30:37 +0800 +Subject: ioctl enhance and rewrite duplicate code + +Signed-off-by: liqiang +--- + qtfs/include/req.h | 2 + + qtfs/qtfs/sb.c | 43 +++++++++----- + qtfs/qtfs_server/fsops.c | 122 ++++++++++++++++----------------------- + 3 files changed, 81 insertions(+), 86 deletions(-) + +diff --git a/qtfs/include/req.h b/qtfs/include/req.h +index 7e0a4b2..407faef 100644 +--- a/qtfs/include/req.h ++++ b/qtfs/include/req.h +@@ -135,6 +135,8 @@ struct qtreq_ioctl { + unsigned int cmd; + unsigned int size; + int fd; ++ int argtype; // 0--use pointer arg, 1--use long arg ++ unsigned long arg; // for long type arg + } d; + + char path[QTFS_TAIL_LEN(struct qtreq_ioctl_len)]; +diff --git a/qtfs/qtfs/sb.c b/qtfs/qtfs/sb.c +index 2038c55..9c03219 100644 +--- a/qtfs/qtfs/sb.c ++++ b/qtfs/qtfs/sb.c +@@ -20,7 +20,7 @@ + #include + #include + #include +- ++#include + + #include "conn.h" + #include "qtfs-mod.h" +@@ -561,7 +561,7 @@ int qtfs_fsync(struct file *file, loff_t start, loff_t end, int datasync) + return 0; + } + +-long qtfs_do_ioctl(struct file *filp, unsigned int cmd, unsigned long arg, unsigned int size) ++long qtfs_do_ioctl(struct file *filp, unsigned int cmd, unsigned long arg, unsigned int size, int argtype) + { + struct qtfs_conn_var_s *pvar = qtfs_conn_get_param(); + struct qtreq_ioctl *req; +@@ -575,19 +575,22 @@ long qtfs_do_ioctl(struct file *filp, unsigned int cmd, unsigned long arg, unsig + return -EINVAL; + } + +- if (size >= MAX_PATH_LEN) { +- WARN_ON(1); ++ req = pvar->conn_ops->get_conn_msg_buf(pvar, QTFS_SEND); ++ rsp = pvar->conn_ops->get_conn_msg_buf(pvar, QTFS_RECV); ++ if (size >= sizeof(req->path)) { ++ qtfs_err("do ioctl failed, size:%u too big:%u", size, sizeof(req->path)); + qtfs_conn_put_param(pvar); + return -EINVAL; + } +- req = pvar->conn_ops->get_conn_msg_buf(pvar, QTFS_SEND); +- rsp = pvar->conn_ops->get_conn_msg_buf(pvar, QTFS_RECV); + + priv = (struct private_data *)filp->private_data; + req->d.fd = priv->fd; +- ++ req->d.argtype = argtype; + req->d.cmd = cmd; +- if (size > 0) { ++ if (argtype) { ++ req->d.arg = arg; ++ len = sizeof(struct qtreq_ioctl) - sizeof(req->path); ++ } else if (size > 0) { + ret = copy_from_user(req->path, (char __user *)arg, size); + if (ret) { + qtfs_err("%s: copy_from_user, size %u failed.", __func__, size); +@@ -597,7 +600,7 @@ long qtfs_do_ioctl(struct file *filp, unsigned int cmd, unsigned long arg, unsig + len = sizeof(struct qtreq_ioctl) - sizeof(req->path) + size; + req->d.size = size; + } else { +- len = sizeof(struct qtreq_ioctl) - sizeof(req->path) + strlen(req->path) + 1; ++ len = sizeof(struct qtreq_ioctl) - sizeof(req->path); + } + + rsp = qtfs_remote_run(pvar, QTFS_REQ_IOCTL, len); +@@ -623,27 +626,41 @@ out: + return (long)ret; + } + ++#define QTFS_IOCTL_CASE_WITH_BREAK(size, argtype)\ ++ {\ ++ ret = qtfs_do_ioctl(filp, cmd, arg, size, argtype);\ ++ break;\ ++ } + long qtfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) + { ++ unsigned int size; ++ long ret; + switch(cmd) { ++ // all case of size 0 type 0 enter here + case FS_IOC_FSGETXATTR: + case TCGETS: +- return qtfs_do_ioctl(filp, cmd, arg, 0); ++ QTFS_IOCTL_CASE_WITH_BREAK(0, 0); ++ // all case of size 0 type 1 enter here ++ case TUNSETPERSIST: ++ QTFS_IOCTL_CASE_WITH_BREAK(0, 1); + case FS_IOC_FSSETXATTR: +- return qtfs_do_ioctl(filp, cmd, arg, sizeof(struct fsxattr)); ++ QTFS_IOCTL_CASE_WITH_BREAK(sizeof(struct fsxattr), 0); + case TCSETS: +- return qtfs_do_ioctl(filp, cmd, arg, sizeof(struct ktermios)); ++ QTFS_IOCTL_CASE_WITH_BREAK(sizeof(struct ktermios), 0); ++ case TUNSETIFF: ++ QTFS_IOCTL_CASE_WITH_BREAK(sizeof(struct ifreq), 0); + default: { + char *fullname = kmalloc(MAX_PATH_LEN, GFP_KERNEL); + if (!fullname) + return -ENOMEM; + memset(fullname, 0, MAX_PATH_LEN); + qtfs_fullname(fullname, filp->f_path.dentry, MAX_PATH_LEN); +- qtfs_err("qtfs ioctl get not support cmd:%d file:%s TCGETS:%d", cmd, fullname, TCGETS); ++ qtfs_err("qtfs ioctl get not support cmd:%d file:%s", cmd, fullname); + kfree(fullname); + return -EOPNOTSUPP; + } + } ++ return ret; + } + + loff_t qtfs_dir_file_llseek(struct file *file, loff_t offset, int whence) +diff --git a/qtfs/qtfs_server/fsops.c b/qtfs/qtfs_server/fsops.c +index 0ae95f3..e8e5742 100644 +--- a/qtfs/qtfs_server/fsops.c ++++ b/qtfs/qtfs_server/fsops.c +@@ -29,6 +29,7 @@ + #include + #include + #include ++#include + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)) + #include + #endif +@@ -105,8 +106,20 @@ static inline void qtfs_inode_info_fill(struct inode_info *ii, struct inode *ino + return; + } + ++#define QTFS_IOCTL_HANDLE_WITH_BREAK(rspsize)\ ++ {\ ++ ret = copy_from_user(rsp->buf, userp->userp, rspsize);\ ++ if (ret) {\ ++ qtfs_err("cmd:%d copy_from_user failed with:%d\n", req->d.cmd, ret);\ ++ rsp->errno = -EFAULT;\ ++ goto err;\ ++ }\ ++ rsp->size = rspsize;\ ++ break;\ ++ } + static int handle_ioctl(struct qtserver_arg *arg) + { ++ unsigned long ioctl_arg; + int ret; + int iret; + struct qtreq_ioctl *req = (struct qtreq_ioctl *)REQ(arg); +@@ -123,82 +136,45 @@ static int handle_ioctl(struct qtserver_arg *arg) + } + mutex_unlock(&fd_bitmap_lock); + +- switch (req->d.cmd) { +- case FS_IOC_FSGETXATTR: +- iret = qtfs_syscall_ioctl(req->d.fd, req->d.cmd, (unsigned long)userp->userp); +- if (iret) { +- qtfs_err("fsgetxattr ioctl failed with %d\n", iret); +- rsp->errno = iret; +- goto err; +- } +- ret = copy_from_user(rsp->buf, userp->userp, sizeof(struct fsxattr)); +- if (ret) { +- qtfs_err("fsgetxattr copy_from_user failed with %d\n", ret); +- rsp->errno = -EFAULT; +- goto err; +- } +- rsp->size = sizeof(struct fsxattr); +- break; +- case FS_IOC_FSSETXATTR: +- if (req->d.size <= 0 || req->d.size > sizeof(req->path) || req->d.size >= userp->size) { +- rsp->errno = -EINVAL; +- goto err; +- } +- ret = copy_to_user(userp->userp, req->path, req->d.size); +- if (ret) { +- qtfs_err("fssetxattr copy_to_user failed with %d\n", ret); +- rsp->errno = -EFAULT; +- goto err; +- } +- iret = qtfs_syscall_ioctl(req->d.fd, req->d.cmd, (unsigned long)userp->userp); +- if (iret) { +- qtfs_err("fssetxattr ioctl failed with %d\n", iret); +- rsp->errno = iret; +- goto err; +- } +- rsp->size = 0; +- break; +- case TCGETS: +- iret = qtfs_syscall_ioctl(req->d.fd, req->d.cmd, (unsigned long)userp->userp); +- if (iret) { +- qtfs_err("ioctl TCGETS failed with %d\n", iret); +- rsp->errno = iret; +- goto err; +- } +- qtfs_info("ioctl TCGETS ret:%d", iret); +- +- ret = copy_from_user(rsp->buf, userp->userp, sizeof(struct ktermios)); +- if (ret) { +- qtfs_err("fsgetxattr copy_from_user failed with %d\n", ret); +- rsp->errno = -EFAULT; +- goto err; +- } +- rsp->size = sizeof(struct ktermios); +- break; +- case TCSETS: +- if (req->d.size <= 0 || req->d.size > sizeof(req->path)) { +- rsp->errno = -EINVAL; +- goto err; +- } +- ret = copy_to_user(userp->userp, req->path, req->d.size); +- if (ret) { +- qtfs_err("tcsets copy_to_user failed with %d\n", ret); +- rsp->errno = -EFAULT; +- goto err; +- } +- qtfs_info("tcsets size:%u sizeof ktermios:%lu", req->d.size, sizeof(struct ktermios)); +- iret = qtfs_syscall_ioctl(req->d.fd, req->d.cmd, (unsigned long)userp->userp); +- if (iret) { +- qtfs_err("tcsets ioctl failed with %d\n", iret); +- rsp->errno = iret; +- goto err; ++ if (req->d.argtype) { ++ ioctl_arg = req->d.arg; ++ } else { ++ if (req->d.size) { ++ if (req->d.size <= 0 || req->d.size > sizeof(req->path) || req->d.size >= userp->size) { ++ rsp->errno = -EINVAL; ++ goto err; ++ } ++ ret = copy_to_user(userp->userp, req->path, req->d.size); ++ if (ret) { ++ qtfs_err("cmd:%d copy_to_user failed with:%d", req->d.cmd, ret); ++ rsp->errno = -EFAULT; ++ goto err; ++ } + } +- rsp->size = 0; +- break; +- default: +- rsp->errno = -EOPNOTSUPP; ++ ioctl_arg = (unsigned long)userp->userp; ++ } ++ iret = qtfs_syscall_ioctl(req->d.fd, req->d.cmd, ioctl_arg); ++ if (iret) { ++ qtfs_err("ioctl fd:%d cmd:%d failed with %d", req->d.fd, req->d.cmd, iret); ++ rsp->errno = iret; + goto err; + } ++ qtfs_info("ioctl fd:%d cmd:%d argtype:%d arg:%lx size:%u successed", req->d.fd, req->d.cmd, req->d.argtype, req->d.arg, req->d.size); ++ switch (req->d.cmd) { ++ case TUNSETPERSIST: ++ case TUNSETIFF: ++ case TCSETS: ++ case FS_IOC_FSSETXATTR: ++ rsp->size = 0; ++ break; ++ case FS_IOC_FSGETXATTR: ++ QTFS_IOCTL_HANDLE_WITH_BREAK(sizeof(struct fsxattr)); ++ case TCGETS: ++ QTFS_IOCTL_HANDLE_WITH_BREAK(sizeof(struct ktermios)); ++ default: ++ rsp->errno = -EOPNOTSUPP; ++ goto err; ++ } + rsp->ret = QTFS_OK; + rsp->errno = iret; + return sizeof(struct qtrsp_ioctl) - sizeof(rsp->buf) + rsp->size; +-- +2.33.0 + diff --git a/0012-port-in-use.patch b/0012-port-in-use.patch new file mode 100644 index 0000000000000000000000000000000000000000..89df6477e88ad9e873e422d085482eb48eab90d9 --- /dev/null +++ b/0012-port-in-use.patch @@ -0,0 +1,127 @@ +From 890082069c4e43fd8d4ec6e96bf851d185195b7d Mon Sep 17 00:00:00 2001 +From: liqiang +Date: Sat, 10 Jun 2023 17:02:53 +0800 +Subject: port in use + +Signed-off-by: liqiang +--- + qtfs/include/conn.h | 12 ++++++++++-- + qtfs/qtfs_common/conn.c | 10 +++++----- + qtfs/qtfs_common/user_engine.c | 5 ++++- + qtfs/qtfs_server/qtfs-server.c | 8 ++++++++ + 4 files changed, 27 insertions(+), 8 deletions(-) + +diff --git a/qtfs/include/conn.h b/qtfs/include/conn.h +index 3b8f1f4..afbb00f 100644 +--- a/qtfs/include/conn.h ++++ b/qtfs/include/conn.h +@@ -46,7 +46,16 @@ extern bool qtfs_epoll_mode; + extern struct qtsock_wl_stru qtsock_wl; + extern struct qtfs_pvar_ops_s qtfs_conn_sock_pvar_ops; + +-#define qtfs_conn_get_param(void) _qtfs_conn_get_param(__func__) ++struct qtfs_conn_var_s *_qtfs_conn_get_param(const char *); ++static inline struct qtfs_conn_var_s *__qtfs_conn_get_param(const char *who_using) ++{ ++ struct qtfs_conn_var_s *p = _qtfs_conn_get_param(who_using); ++ if (IS_ERR_OR_NULL(p)) ++ return NULL; ++ return p; ++} ++#define qtfs_conn_get_param(void) __qtfs_conn_get_param(__func__) ++#define qtfs_conn_get_param_errcode(void) _qtfs_conn_get_param(__func__) + + #define QTFS_CONN_SOCK_TYPE "socket" + #define QTFS_CONN_PCIE_TYPE "pcie" +@@ -172,7 +181,6 @@ void *qtfs_conn_msg_buf(struct qtfs_conn_var_s *pvar, int dir); + void qtfs_conn_param_init(void); + void qtfs_conn_param_fini(void); + +-struct qtfs_conn_var_s *_qtfs_conn_get_param(const char *); + void qtfs_conn_put_param(struct qtfs_conn_var_s *pvar); + struct qtfs_conn_var_s *qtfs_epoll_establish_conn(void); + void qtfs_epoll_cut_conn(struct qtfs_conn_var_s *pvar); +diff --git a/qtfs/qtfs_common/conn.c b/qtfs/qtfs_common/conn.c +index 56b2b12..ab84181 100644 +--- a/qtfs/qtfs_common/conn.c ++++ b/qtfs/qtfs_common/conn.c +@@ -580,7 +580,7 @@ retry: + } + if (ret != 0) { + qtfs_conn_put_param(pvar); +- return NULL; ++ return (IS_ERR_VALUE((long)ret) ? ERR_PTR((long)ret) : NULL); + } + strlcpy(pvar->who_using, func, QTFS_FUNCTION_LEN); + return pvar; +@@ -636,18 +636,18 @@ retry: + qtfs_err("qtfs get param active connection failed, ret:%d, curstate:%s", ret, QTCONN_CUR_STATE(pvar)); + // put to vld list + qtfs_conn_put_param(pvar); +- return NULL; ++ return (IS_ERR_VALUE((long)ret) ? ERR_PTR((long)ret) : NULL); + } + qtfs_thread_var[pvar->cur_threadidx] = pvar; + #else + pvar->cs = QTFS_CONN_SOCK_SERVER; + if (!pvar->conn_ops->conn_inited(pvar)) { +- if (qtfs_sm_active(pvar)) { ++ if ((ret = qtfs_sm_active(pvar)) != 0) { + qtfs_err("qtfs get param active connection failed, ret:%d, curstate:%s", ret, QTCONN_CUR_STATE(pvar)); + // put to vld list + mutex_unlock(&g_param_mutex); + qtfs_conn_put_param(pvar); +- return NULL; ++ return (IS_ERR_VALUE((long)ret) ? ERR_PTR((long)ret) : NULL); + } + mutex_unlock(&g_param_mutex); + } else { +@@ -657,7 +657,7 @@ retry: + if (ret) { + qtfs_err("qtfs get param active connection failed, ret:%d curstate:%s", ret, QTCONN_CUR_STATE(pvar)); + qtfs_conn_put_param(pvar); +- return NULL; ++ return (IS_ERR_VALUE((long)ret) ? ERR_PTR((long)ret) : NULL); + } + } + #endif +diff --git a/qtfs/qtfs_common/user_engine.c b/qtfs/qtfs_common/user_engine.c +index 521ebe4..919da11 100644 +--- a/qtfs/qtfs_common/user_engine.c ++++ b/qtfs/qtfs_common/user_engine.c +@@ -105,9 +105,12 @@ static struct qtfs_server_userp_s *qtfs_engine_thread_init(int fd, int thread_nu + } + } + struct qtfs_thread_init_s init_userp; ++ int ret; + init_userp.thread_nums = thread_nums; + init_userp.userp = userp; +- if (ioctl(fd, QTFS_IOCTL_THREAD_INIT, (unsigned long)&init_userp) == QTERROR) { ++ ret = ioctl(fd, QTFS_IOCTL_THREAD_INIT, (unsigned long)&init_userp); ++ if (ret != QTOK) { ++ engine_err("Engine thread init failed reason:%s", (ret == EADDRINUSE) ? strerror(EADDRINUSE) : "userp init failed."); + goto rollback; + } + return userp; +diff --git a/qtfs/qtfs_server/qtfs-server.c b/qtfs/qtfs_server/qtfs-server.c +index 003c361..729097b 100644 +--- a/qtfs/qtfs_server/qtfs-server.c ++++ b/qtfs/qtfs_server/qtfs-server.c +@@ -192,6 +192,14 @@ long qtfs_server_misc_ioctl(struct file *file, unsigned int cmd, unsigned long a + struct qtfs_thread_init_s init_userp; + switch (cmd) { + case QTFS_IOCTL_THREAD_INIT: ++ pvar = qtfs_conn_get_param_errcode(); ++ if (IS_ERR_OR_NULL(pvar)) { ++ qtfs_err("init pvar get failed, pvar:%ld", (long)pvar); ++ if (PTR_ERR(pvar) == -EADDRINUSE) ++ return EADDRINUSE; ++ } else { ++ qtfs_conn_put_param(pvar); ++ } + if (!write_trylock(&g_userp_rwlock)) { + qtfs_err("try lock userps failed."); + return QTERROR; +-- +2.33.0 + diff --git a/0013-ioctl-add-cmd.patch b/0013-ioctl-add-cmd.patch new file mode 100644 index 0000000000000000000000000000000000000000..f87dfd0a865e4c42b61648e8073962ebf55e19a7 --- /dev/null +++ b/0013-ioctl-add-cmd.patch @@ -0,0 +1,39 @@ +From 31262c9f982d59bf7f407f2f698933515dc4c8c7 Mon Sep 17 00:00:00 2001 +From: liqiang +Date: Mon, 12 Jun 2023 11:28:27 +0800 +Subject: ioctl add cmd + +Signed-off-by: liqiang +--- + qtfs/qtfs/sb.c | 1 + + qtfs/qtfs_server/fsops.c | 2 ++ + 2 files changed, 3 insertions(+) + +diff --git a/qtfs/qtfs/sb.c b/qtfs/qtfs/sb.c +index 9c03219..f557e6d 100644 +--- a/qtfs/qtfs/sb.c ++++ b/qtfs/qtfs/sb.c +@@ -648,6 +648,7 @@ long qtfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) + case TCSETS: + QTFS_IOCTL_CASE_WITH_BREAK(sizeof(struct ktermios), 0); + case TUNSETIFF: ++ case SIOCGIFHWADDR: + QTFS_IOCTL_CASE_WITH_BREAK(sizeof(struct ifreq), 0); + default: { + char *fullname = kmalloc(MAX_PATH_LEN, GFP_KERNEL); +diff --git a/qtfs/qtfs_server/fsops.c b/qtfs/qtfs_server/fsops.c +index e8e5742..727c4e1 100644 +--- a/qtfs/qtfs_server/fsops.c ++++ b/qtfs/qtfs_server/fsops.c +@@ -171,6 +171,8 @@ static int handle_ioctl(struct qtserver_arg *arg) + QTFS_IOCTL_HANDLE_WITH_BREAK(sizeof(struct fsxattr)); + case TCGETS: + QTFS_IOCTL_HANDLE_WITH_BREAK(sizeof(struct ktermios)); ++ case SIOCGIFHWADDR: ++ QTFS_IOCTL_HANDLE_WITH_BREAK(sizeof(struct ifreq)); + default: + rsp->errno = -EOPNOTSUPP; + goto err; +-- +2.33.0 + diff --git a/0014-engine-running-lock.patch b/0014-engine-running-lock.patch new file mode 100644 index 0000000000000000000000000000000000000000..2b6abad53fd5c1cbaa0355b55e440159652d0506 --- /dev/null +++ b/0014-engine-running-lock.patch @@ -0,0 +1,54 @@ +From a79ba9896c37d30cd1901f7f54e0507adb9aabda Mon Sep 17 00:00:00 2001 +From: liqiang +Date: Mon, 12 Jun 2023 11:34:09 +0800 +Subject: engine running lock + +Signed-off-by: liqiang +--- + qtfs/qtfs_common/user_engine.c | 16 +++++++++++++++- + 1 file changed, 15 insertions(+), 1 deletion(-) + +diff --git a/qtfs/qtfs_common/user_engine.c b/qtfs/qtfs_common/user_engine.c +index 919da11..7455413 100644 +--- a/qtfs/qtfs_common/user_engine.c ++++ b/qtfs/qtfs_common/user_engine.c +@@ -33,7 +33,7 @@ + #include + #include + #include +- ++#include + #include + + #include "comm.h" +@@ -68,6 +68,16 @@ struct engine_arg { + + #define QTFS_USERP_SIZE QTFS_USERP_MAXSIZE + #define QTFS_SERVER_FILE "/dev/qtfs_server" ++#define ENGINE_LOCK_ADDR "/var/run/qtfs/engine.lock" ++ ++int engine_socket_lock(void) ++{ ++ int lock_fd = open(ENGINE_LOCK_ADDR, O_RDONLY | O_CREAT, 0600); ++ if (lock_fd == -1) ++ return -EINVAL; ++ ++ return flock(lock_fd, LOCK_EX | LOCK_NB); ++} + + int qtfs_fd; + int engine_run = 1; +@@ -365,6 +375,10 @@ int main(int argc, char *argv[]) + engine_out(" Example: %s 16 1 192.168.10.10 12121 192.168.10.11 12121.", argv[0]); + return -1; + } ++ if (engine_socket_lock() < 0) { ++ engine_err("Engine is running."); ++ return -1; ++ } + if (qtfs_engine_env_check(argv) < 0) { + engine_err("Environment check failed, engine exit."); + return -1; +-- +2.33.0 + diff --git a/0015-Adapt-for-kernel-6.4.patch b/0015-Adapt-for-kernel-6.4.patch new file mode 100644 index 0000000000000000000000000000000000000000..62dcc1dc23ab1719b67f732d5b839a4baa300b5d --- /dev/null +++ b/0015-Adapt-for-kernel-6.4.patch @@ -0,0 +1,308 @@ +From 8e66cbde95f58c3a2a18351b81cae29bc69f760d Mon Sep 17 00:00:00 2001 +From: Weifeng Su +Date: Tue, 15 Aug 2023 07:06:03 +0000 +Subject: [PATCH] Adapt for kernel 6.4 + +The file system inode ops need struct mnt_idmap parameter in kernel 6.4 + +Signed-off-by: Weifeng Su +--- + qtfs/qtfs/ops.h | 4 +++- + qtfs/qtfs/proc.c | 8 ++++++-- + qtfs/qtfs/sb.c | 35 +++++++++++++++++++++++++++-------- + qtfs/qtfs/xattr.c | 32 ++++++++++++++++++++++++++++---- + qtfs/qtfs_common/conn.c | 5 ++++- + qtfs/qtfs_server/fsops.c | 25 +++++++++++++++++++------ + 6 files changed, 87 insertions(+), 22 deletions(-) + +diff --git a/qtfs/qtfs/ops.h b/qtfs/qtfs/ops.h +index 560be74..bdb2628 100644 +--- a/qtfs/qtfs/ops.h ++++ b/qtfs/qtfs/ops.h +@@ -29,7 +29,9 @@ bool is_sb_proc(struct super_block *sb); + struct inode *qtfs_iget(struct super_block *sb, struct inode_info *ii); + const char *qtfs_getlink(struct dentry *dentry, + struct inode *inode, struct delayed_call *done); +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0)) ++int qtfs_getattr(struct mnt_idmap *idmap, const struct path *, struct kstat *, u32, unsigned int); ++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) + int qtfs_getattr(struct user_namespace *mnt_userns, const struct path *, struct kstat *, u32, unsigned int); + #else + int qtfs_getattr(const struct path *, struct kstat *, u32, unsigned int); +diff --git a/qtfs/qtfs/proc.c b/qtfs/qtfs/proc.c +index e56bd8c..70238ea 100644 +--- a/qtfs/qtfs/proc.c ++++ b/qtfs/qtfs/proc.c +@@ -26,7 +26,9 @@ + struct dentry *qtfs_proc_lookup(struct inode *parent_inode, struct dentry *child_dentry, unsigned int flags); + const char *qtfs_proc_getlink(struct dentry *dentry, struct inode *inode, struct delayed_call *done); + +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0)) ++int qtfs_proc_getattr(struct mnt_idmap *idmap, const struct path *path, struct kstat *stat, u32 req_mask, unsigned int flags); ++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) + int qtfs_proc_getattr(struct user_namespace *mnt_userns, const struct path *path, struct kstat *stat, u32 req_mask, unsigned int flags); + #else + int qtfs_proc_getattr(const struct path *path, struct kstat *stat, u32 req_mask, unsigned int flags); +@@ -240,7 +242,9 @@ link_local: + return link; + } + +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0)) ++int qtfs_proc_getattr(struct mnt_idmap *idmap, const struct path *path, struct kstat *stat, u32 req_mask, unsigned int flags) ++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) + int qtfs_proc_getattr(struct user_namespace *mnt_userns, const struct path *path, struct kstat *stat, u32 req_mask, unsigned int flags) + #else + int qtfs_proc_getattr(const struct path *path, struct kstat *stat, u32 req_mask, unsigned int flags) +diff --git a/qtfs/qtfs/sb.c b/qtfs/qtfs/sb.c +index fa3b5ac..faafa76 100644 +--- a/qtfs/qtfs/sb.c ++++ b/qtfs/qtfs/sb.c +@@ -907,7 +907,9 @@ int qtfs_new_entry(struct inode *inode, struct dentry *dentry) + return 0; + } + +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0)) ++int qtfs_mkdir(struct mnt_idmap *mnt_userns, struct inode *dir, struct dentry *dentry, umode_t mode) ++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) + int qtfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir, struct dentry *dentry, umode_t mode) + #else + int qtfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) +@@ -946,7 +948,9 @@ int qtfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) + return ret; + } + +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0)) ++int qtfs_create(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, umode_t mode, bool excl) ++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) + int qtfs_create(struct user_namespace *mnt_userns, struct inode *dir, struct dentry *dentry, umode_t mode, bool excl) + #else + int qtfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl) +@@ -990,7 +994,9 @@ int qtfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool exc + return ret ? ret : ret2; + } + +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0)) ++int qtfs_mknod(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) ++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) + int qtfs_mknod(struct user_namespace *mnt_userns, struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) + #else + int qtfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) +@@ -1258,7 +1264,9 @@ err_end: + return error; + } + +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0)) ++int qtfs_symlink(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, const char *symname) ++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) + int qtfs_symlink(struct user_namespace *mnt_userns, struct inode *dir, struct dentry *dentry, const char *symname) + #else + int qtfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) +@@ -1307,7 +1315,9 @@ err_end: + return error; + } + +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0)) ++int qtfs_getattr(struct mnt_idmap *idmap, const struct path *path, struct kstat *stat, u32 req_mask, unsigned int flags) ++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) + int qtfs_getattr(struct user_namespace *mnt_userns, const struct path *path, struct kstat *stat, u32 req_mask, unsigned int flags) + #else + int qtfs_getattr(const struct path *path, struct kstat *stat, u32 req_mask, unsigned int flags) +@@ -1360,7 +1370,9 @@ int qtfs_getattr(const struct path *path, struct kstat *stat, u32 req_mask, unsi + return 0; + } + +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0)) ++int qtfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry, struct iattr *attr) ++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) + int qtfs_setattr(struct user_namespace *mnt_userns, struct dentry *dentry, struct iattr *attr) + #else + int qtfs_setattr(struct dentry *dentry, struct iattr *attr) +@@ -1463,7 +1475,12 @@ const char *qtfs_getlink(struct dentry *dentry, + qtfs_conn_put_param(pvar); + return link; + } +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0)) ++int qtfs_rename(struct mnt_idmap *idmap, struct inode *old_dir, ++ struct dentry *old_dentry, struct inode *new_dir, ++ struct dentry *new_dentry, unsigned int flags) ++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) + int qtfs_rename(struct user_namespace *mnt_userns, struct inode *old_dir, + struct dentry *old_dentry, struct inode *new_dir, + struct dentry *new_dentry, unsigned int flags) +@@ -1604,7 +1621,9 @@ static int qtfs_fill_super(struct super_block *sb, void *priv_data, int silent) + + root_inode = new_inode(sb); + root_inode->i_ino = 1; +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0)) ++ inode_init_owner(&nop_mnt_idmap, root_inode, NULL, mode); ++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) + inode_init_owner(&init_user_ns, root_inode, NULL, mode); + #else + inode_init_owner(root_inode, NULL, mode); +diff --git a/qtfs/qtfs/xattr.c b/qtfs/qtfs/xattr.c +index 3ba7704..4d15daf 100644 +--- a/qtfs/qtfs/xattr.c ++++ b/qtfs/qtfs/xattr.c +@@ -73,7 +73,13 @@ static int qtfs_xattr_set(const struct xattr_handler *handler, + size_t size, int flags); + + static int +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0)) ++qtfs_xattr_user_set(const struct xattr_handler *handler, ++ struct mnt_idmap *idmap, ++ struct dentry *unused, struct inode *inode, ++ const char *name, const void *value, ++ size_t size, int flags) ++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) + qtfs_xattr_user_set(const struct xattr_handler *handler, + struct user_namespace *mnt_userns, + struct dentry *unused, struct inode *inode, +@@ -91,7 +97,13 @@ qtfs_xattr_user_set(const struct xattr_handler *handler, + } + + static int +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0)) ++qtfs_xattr_trusted_set(const struct xattr_handler *handler, ++ struct mnt_idmap *idmap, ++ struct dentry *unused, struct inode *inode, ++ const char *name, const void *value, ++ size_t size, int flags) ++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) + qtfs_xattr_trusted_set(const struct xattr_handler *handler, + struct user_namespace *mnt_userns, + struct dentry *unused, struct inode *inode, +@@ -108,7 +120,13 @@ qtfs_xattr_trusted_set(const struct xattr_handler *handler, + } + + static int +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0)) ++qtfs_xattr_security_set(const struct xattr_handler *handler, ++ struct mnt_idmap *idmap, ++ struct dentry *unused, struct inode *inode, ++ const char *name, const void *value, ++ size_t size, int flags) ++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) + qtfs_xattr_security_set(const struct xattr_handler *handler, + struct user_namespace *mnt_userns, + struct dentry *unused, struct inode *inode, +@@ -270,7 +288,13 @@ const struct xattr_handler qtfs_xattr_security_handler = { + + #ifndef KVER_4_19 + static int +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0)) ++qtfs_xattr_hurd_set(const struct xattr_handler *handler, ++ struct mnt_idmap *idmap, ++ struct dentry *unused, struct inode *inode, ++ const char *name, const void *value, ++ size_t size, int flags) ++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) + qtfs_xattr_hurd_set(const struct xattr_handler *handler, + struct user_namespace *mnt_userns, + struct dentry *unused, struct inode *inode, +diff --git a/qtfs/qtfs_common/conn.c b/qtfs/qtfs_common/conn.c +index 10b4cbe..cc59d52 100644 +--- a/qtfs/qtfs_common/conn.c ++++ b/qtfs/qtfs_common/conn.c +@@ -167,8 +167,11 @@ int qtfs_uds_remote_connect_user(int fd, struct sockaddr __user *addr, int len) + if (f.file == NULL) { + return -EBADF; + } +- ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0)) ++ sock =sock_from_file(f.file); ++#else + sock = sock_from_file(f.file, &err); ++#endif + if (!sock) { + goto end; + } +diff --git a/qtfs/qtfs_server/fsops.c b/qtfs/qtfs_server/fsops.c +index 5485d04..5f3f779 100644 +--- a/qtfs/qtfs_server/fsops.c ++++ b/qtfs/qtfs_server/fsops.c +@@ -30,7 +30,10 @@ + #include + #include + #include +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0)) ++#include ++#include ++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)) + #include + #endif + +@@ -860,7 +863,9 @@ static int handle_setattr(struct qtserver_arg *arg) + } + + inode_lock(inode); +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0)) ++ rsp->errno = notify_change(&nop_mnt_idmap, path.dentry, &req->attr, NULL); ++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) + rsp->errno = notify_change(&init_user_ns, path.dentry, &req->attr, NULL); + #else + rsp->errno = notify_change(path.dentry, &req->attr, NULL); +@@ -938,7 +943,9 @@ retry: + req->mode &= ~current_umask(); + error = security_path_mknod(&path, dent, req->mode, req->dev); + if (!error) +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0)) ++ error = vfs_mknod(&nop_mnt_idmap, path.dentry->d_inode, dent, req->mode, req->dev); ++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) + error = vfs_mknod(&init_user_ns, path.dentry->d_inode, dent, req->mode, req->dev); + #else + error = vfs_mknod(path.dentry->d_inode, dent, req->mode, req->dev); +@@ -1046,7 +1053,9 @@ retry: + qtfs_err("handle_symlink: newname(%s), oldname(%s) in kern_path_create %d\n", newname, oldname, error); + return sizeof(struct qtrsp_symlink); + } +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0)) ++ rsp->errno = vfs_symlink(&nop_mnt_idmap, path.dentry->d_inode, dentry, oldname); ++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) + rsp->errno = vfs_symlink(&init_user_ns, path.dentry->d_inode, dentry, oldname); + #else + rsp->errno = vfs_symlink(path.dentry->d_inode, dentry, oldname); +@@ -1188,7 +1197,9 @@ int handle_xattrset(struct qtserver_arg *arg) + path_put(&path); + goto err_handle; + } +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0)) ++ rsp->errno = vfs_setxattr(&nop_mnt_idmap, path.dentry, &req->buf[req->d.pathlen], &req->buf[req->d.pathlen + req->d.namelen], req->d.size, req->d.flags); ++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) + rsp->errno = vfs_setxattr(&init_user_ns, path.dentry, &req->buf[req->d.pathlen], &req->buf[req->d.pathlen + req->d.namelen], req->d.size, req->d.flags); + #else + rsp->errno = vfs_setxattr(path.dentry, &req->buf[req->d.pathlen], &req->buf[req->d.pathlen + req->d.namelen], req->d.size, req->d.flags); +@@ -1238,7 +1249,9 @@ int handle_xattrget(struct qtserver_arg *arg) + goto err_handle; + } + } +-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0)) ++ error = vfs_getxattr(&nop_mnt_idmap, path.dentry, req->d.prefix_name, kvalue, req->d.size); ++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) + error = vfs_getxattr(&init_user_ns, path.dentry, req->d.prefix_name, kvalue, req->d.size); + #else + error = vfs_getxattr(path.dentry, req->d.prefix_name, kvalue, req->d.size); +-- +2.33.0 + diff --git a/dpu-utilities.spec b/dpu-utilities.spec index 71e9d31c3976b131980f7abd3fc9cfeb1653526f..b91110342f2ac223d849ed1c3896770fa508ea6a 100644 --- a/dpu-utilities.spec +++ b/dpu-utilities.spec @@ -1,7 +1,7 @@ Name: dpu-utilities Summary: openEuler dpu utilities -Version: 1.1 -Release: 4 +Version: 1.4 +Release: 3 License: GPL-2.0 Source: https://gitee.com/openeuler/dpu-utilities/repository/archive/v%{version}.tar.gz ExclusiveOS: linux @@ -10,18 +10,24 @@ BuildRoot: %{_tmppath}/%{name}-%{version}-root Conflicts: %{name} < %{version}-%{release} Provides: %{name} = %{version}-%{release} %define kernel_version %(ver=`rpm -qa|grep kernel-devel`;echo ${ver#*kernel-devel-}) -BuildRequires: kernel-devel >= 5.10, gcc, make, glib2-devel, glib2 -BuildRequires: golang -Patch0: 0001-add-path-put-in-xattr-set.patch -Patch1: 0002-Add-drop-link-and-dentry-invalid-in-unlink-and-rmdir.patch -Patch2: 0003-enable-rexec-read-net-addr-from-config-file.patch -Patch3: 0004-Fix-inode-sync-error-between-client-and-server.patch -Patch4: 0005-Add-whitelist-of-qtfs.patch -Patch5: 0006-Fix-error-of-getxattr-and-listxattr.patch -Patch6: 0007-Add-whitelist-of-rexec.patch -Patch7: 0008-Add-udsproxy.patch -Patch8: 0009-Add-rexec-shim.patch -Patch9: 0010-Adapt-to-kernel-6.1-file-system-interface-changes.patch +BuildRequires: kernel-devel >= 5.10, gcc, make, json-c-devel, glib2-devel + +Patch1: 0001-rewrite-client-rexec_run.patch +Patch2: 0002-uds-add-vsock-mode.patch +Patch3: 0003-fix-a-rexec_server-bug-on-child-process.patch +Patch4: 0004-add-uds-test-mode-in-engine-compile.patch +Patch5: 0005-modify-qtfs_dentry_revalidate.patch +Patch6: 0006-add-cmake-compile-for-user-binary-and-so.patch +Patch7: 0007-uds-remove-MSG_WAITALL-flags-to-timeout.patch +Patch8: 0008-Modify-the-logic-of-rexec-proxy-process-exit-by-mist.patch +Patch9: 0009-Keep-doc-same-with-docs-in-openEuler.patch +Patch10: 0010-update-libvirt-doc.patch +Patch11: 0011-ioctl-enhance-and-rewrite-duplicate-code.patch +Patch12: 0012-port-in-use.patch +Patch13: 0013-ioctl-add-cmd.patch +Patch14: 0014-engine-running-lock.patch +Patch15: 0015-Adapt-for-kernel-6.4.patch + %description This package contains the software utilities on dpu. @@ -34,12 +40,14 @@ imageTailor configration files for dpuos %package -n qtfs-client Summary: Client of qtfs +Requires: json-c, glib2 %description -n qtfs-client qtfs is a shared file system, this is the client of qtfs. %package -n qtfs-server Summary: Server of qtfs +Requires: json-c, glib2 %description -n qtfs-server qtfs is a shared file system, this is the server of qtfs. @@ -58,18 +66,32 @@ cd %_builddir/%{name}-v%{version}/qtfs/rexec make cd %_builddir/%{name}-v%{version}/qtfs/ipc make +cd %_builddir/%{name}-v%{version}/qtfs/qtinfo +export role=client +make qtcfg +mv qtcfg qtcfg_client +make clean +export role=server +make qtcfg %install -mkdir -p $RPM_BUILD_ROOT/lib/modules/%{kernel_version}/extra +mkdir -p $RPM_BUILD_ROOT/lib/modules/%{kernel_version}//extra mkdir -p $RPM_BUILD_ROOT/usr/bin/ -mkdir -p ${RPM_BUILD_ROOT}/usr/lib64/ +mkdir -p $RPM_BUILD_ROOT/usr/lib/ +mkdir -p $RPM_BUILD_ROOT/usr/local/bin +mkdir -p $RPM_BUILD_ROOT/etc/qtfs +mkdir -p $RPM_BUILD_ROOT/etc/rexec install %_builddir/%{name}-v%{version}/qtfs/qtfs/qtfs.ko $RPM_BUILD_ROOT/lib/modules/%{kernel_version}/extra install %_builddir/%{name}-v%{version}/qtfs/qtfs_server/qtfs_server.ko $RPM_BUILD_ROOT/lib/modules/%{kernel_version}/extra install -m 0700 %_builddir/%{name}-v%{version}/qtfs/qtfs_server/engine $RPM_BUILD_ROOT/usr/bin/ install -m 0700 %_builddir/%{name}-v%{version}/qtfs/rexec/rexec ${RPM_BUILD_ROOT}/usr/bin/ install -m 0700 %_builddir/%{name}-v%{version}/qtfs/rexec/rexec_server ${RPM_BUILD_ROOT}/usr/bin/ install -m 0700 %_builddir/%{name}-v%{version}/qtfs/ipc/udsproxyd ${RPM_BUILD_ROOT}/usr/bin/ -install -m 0700 %_builddir/%{name}-v%{version}/qtfs/ipc/libudsproxy.so ${RPM_BUILD_ROOT}/usr/lib64/ +install -m 0700 %_builddir/%{name}-v%{version}/qtfs/ipc/libudsproxy.so ${RPM_BUILD_ROOT}/usr/lib/ +install -m 0700 %_builddir/%{name}-v%{version}/qtfs/qtinfo/qtcfg ${RPM_BUILD_ROOT}/usr/bin/ +install -m 0700 %_builddir/%{name}-v%{version}/qtfs/qtinfo/qtcfg_client ${RPM_BUILD_ROOT}/usr/local/bin/qtcfg +install -m 0400 %_builddir/%{name}-v%{version}/qtfs/config/rexec/whitelist ${RPM_BUILD_ROOT}/etc/rexec +install -m 0400 %_builddir/%{name}-v%{version}/qtfs/config/qtfs/whitelist ${RPM_BUILD_ROOT}/etc/qtfs mkdir -p $RPM_BUILD_ROOT/opt/imageTailor cp -rf %_builddir/%{name}-v%{version}/dpuos/image_tailor_cfg/custom $RPM_BUILD_ROOT/opt/imageTailor cp -rf %_builddir/%{name}-v%{version}/dpuos/image_tailor_cfg/kiwi $RPM_BUILD_ROOT/opt/imageTailor @@ -99,17 +121,21 @@ fi %files -n qtfs-client -/lib/modules/%{kernel_version}/extra/qtfs.ko -%attr(0700, root, root) /usr/bin/rexec_server -%attr(0700, root, root) /usr/bin/rexec -%attr(0700, root, root) /usr/bin/udsproxyd -%attr(0700, root, root) /usr/lib64/libudsproxy.so +%attr(0644, root, root) /lib/modules/%{kernel_version}/extra/qtfs.ko +%attr(0500, root, root) /usr/bin/rexec_server +%attr(0500, root, root) /usr/bin/rexec +%attr(0500, root, root) /usr/lib/libudsproxy.so +%attr(0500, root, root) /usr/bin/udsproxyd +%attr(0500, root, root) /usr/local/bin/qtcfg %files -n qtfs-server -/lib/modules/%{kernel_version}/extra/qtfs_server.ko -%attr(0700, root, root) /usr/bin/engine -%attr(0700, root, root)/usr/bin/rexec_server -%attr(0700, root, root)/usr/bin/rexec +%attr(0644, root, root) /lib/modules/%{kernel_version}/extra/qtfs_server.ko +%attr(0500, root, root) /usr/bin/engine +%attr(0500, root, root) /usr/bin/rexec_server +%attr(0500, root, root) /usr/bin/rexec +%attr(0500, root, root) /usr/bin/qtcfg +%attr(0400, root, root) /etc/qtfs/whitelist +%attr(0400, root, root) /etc/rexec/whitelist %files -n dpuos-imageTailor-config /opt/imageTailor/custom/* @@ -121,14 +147,29 @@ sed -i '/# product cut_conf/a\dpuos kiwi/minios/cfg_dpuos yes' /opt/imageT sed -i '//a\dpuos 1 rpm-dir euler_base' /opt/imageTailor/repos/RepositoryRule.conf %changelog -* Thu Feb 09 2023 YangXin <245051644@qq.com> 1.1-4 -- Add whitelist to qtfs and rexec, fix errors, add udsproxy. -* Thu Dec 15 2022 YangXin <245051644@qq.com> 1.1-3 +* Mon Aug 21 2023 Weifeng Su 1.4-3 +- Adapt for kernel 6.4 + +* Mon Jun 12 2023 Weifeng Su 1.4-2 +- Sync patches from source + +* Fri Jun 2 2023 Weifeng Su 1.4-1 +- Upgrade dpu-utilities version to 1.4 + +* Tue Mar 21 2023 Weifeng Su 1.3-1 +- Upgrade dpu-utilities version to 1.3 + +* Thu Dec 15 2022 YangXin <245051644@qq.com> 1.1-4 - Fix inode sync error between client and server. -* Thu Dec 08 2022 YangXin <245051644@qq.com> 1.1-2 -- Fix error of qtfs and modify rexec to enable reading net addr from file. +* Thu Dec 8 2022 Weifeng Su 1.1-3 +- Sync patches from master + +* Thu Dec 1 2022 Weifeng Su 1.1-2 +- add path put in xattr set + * Mon Nov 28 2022 Weifeng Su 1.1-1 - Upgrade dpu-utilities version to 1.1 + * Wed Aug 17 2022 yangxin <245051644@qq.com> 1.0-2 - Split dpu-utilities into three packages. * Fri Aug 12 2022 yangxin <245051644@qq.com> 1.0-1 diff --git a/dpu-utilities.yaml b/dpu-utilities.yaml deleted file mode 100644 index 524d4f7b136a5581d6ffbe8b777790d6fe1bb02d..0000000000000000000000000000000000000000 --- a/dpu-utilities.yaml +++ /dev/null @@ -1,4 +0,0 @@ -version_control: gitee -src_repo: openeuler/dpu-utilities -tag_prefix: "^v" -separator: "." \ No newline at end of file diff --git a/v1.1.tar.gz b/v1.1.tar.gz deleted file mode 100644 index 9a38baa8ef719584d666f446bc46a73e6391a81e..0000000000000000000000000000000000000000 Binary files a/v1.1.tar.gz and /dev/null differ diff --git a/v1.4.tar.gz b/v1.4.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..786b99f3164f87b3bd097f0f8933644fa6060c30 Binary files /dev/null and b/v1.4.tar.gz differ