[patch 13/56] openmosix/openmosix-kcomd-daemon-code.patch
Florian Delizy <[email protected]> Thu, 02 Nov 2006 22:56:03 +0100
| Newsgroups | gmane.linux.cluster.openmosix.devel |
|---|---|
| Message-ID | <[email protected]> |
------------------------------------------------------------------------- Using Tomcat but need to do more? Need to support web services, security? Get stuff done quickly with pre-integrated technology to make your job easier Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642 _______________________________________________ openMosix-devel mailing list openMosix-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org https://lists.sourceforge.net/lists/listinfo/openmosix-devel
openmosix-kcomd-daemon-code.patch
(text/x-patch, 29.8 KB)
Index: linux/hpc/kcom.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/hpc/kcom.c 2006-11-02 22:51:51.000000000 +0100 @@ -0,0 +1,1061 @@ +/* + * Copyright (C) 2006 Matt Dew <[email protected]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 only. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/sched.h> +#include <linux/socket.h> +#include <linux/in.h> +#include <linux/in6.h> +#include <linux/net.h> +#include <linux/syscalls.h> +#include <net/sock.h> +#include <net/tcp.h> +#define _HPC_KCOMC_H 1 +#include <hpc/kcom.h> +#include <hpc/prototype.h> + + +/** + * pkt_data_read + * + * Description: + * read the data that was send following the pkt header. + * wait until all data has been read. + * The ->len field = size of the data in bytes. + **/ +int pkt_data_read(struct kcom_node *node, struct kcom_pkt *pkt, int len, char *data) +{ + struct socket *sock=node->sock; + struct iovec iov; + struct msghdr msg = { NULL, 0, &iov, 1, NULL, 0, MSG_WAITALL | MSG_NOSIGNAL }; + mm_segment_t oldfs; + int i; + char buf[32]; + + iov.iov_base = data; + iov.iov_len = len; + + // Too small of a packet gets delayed before being sent. Even with TCP_NODELAY + if (len < 32) { + iov.iov_base = &buf; + iov.iov_len = 32; + } + + oldfs = get_fs(); + set_fs(KERNEL_DS); + + while (iov.iov_len > 0) { + i = sock_recvmsg(sock, &msg, iov.iov_len, msg.msg_flags); + if ((i == -ENOSPC) || (i == -EAGAIN)) { + schedule_timeout(HZ/1000); + continue; + } + if (i < 0) { + printk("ERROR %d receiving data.\n", i); + set_fs(oldfs); + return -1; + } + iov.iov_base += i; + } + + set_fs(oldfs); + + if (len < 32) { + memcpy(data, buf, len); + } + + return len; +} +EXPORT_SYMBOL_GPL(pkt_data_read); + +/** + * pkt_hdr_read + * + * Description: + * read the pkt header of the data transmission. + * The hdr indicates the type and size of the data. + * All packet headers are the same size. + **/ +struct kcom_pkt* pkt_hdr_read(struct kcom_node *node) +{ + struct iovec iov; + struct msghdr msg = { NULL, 0, &iov, 1, NULL, 0, MSG_WAITALL | MSG_NOSIGNAL }; + struct kcom_pkt *recv_kcom_pkt; + mm_segment_t oldfs; + struct socket *sock=node->sock; + int i; + + recv_kcom_pkt=kmem_cache_alloc(kcom_pkt_cachep, SLAB_KERNEL); + iov.iov_base = recv_kcom_pkt; + iov.iov_len = sizeof(*recv_kcom_pkt); + + oldfs = get_fs(); + set_fs(KERNEL_DS); + while (iov.iov_len > 0) { + i = sock_recvmsg(sock, &msg, iov.iov_len, msg.msg_flags); + if ((i == -ENOSPC) || (i == -EAGAIN)) { + schedule_timeout(HZ/1000); + continue; + } + if (i < 0) { + printk("ERROR %d receiving header.\n", i); + set_fs(oldfs); + return NULL; + } + iov.iov_base += i; + } + set_fs(oldfs); + + if (iov.iov_len==0) // all expected data received. + return recv_kcom_pkt; + else + return NULL; +} +EXPORT_SYMBOL_GPL(pkt_hdr_read); + + +/** + * alloc_fd_bitmap + * + * Description: + * Allocate a large enough file descriptor bitmap + * for the do_select function to operate correctly + * on all open sockets. + * If more space needs to be allocated, it will be + **/ +int alloc_fd_bitmap(int fd) +{ + struct kcom_node *node; + int size; + int n=fd; + + if (fd <= maxfds) + return 0; + + n = max(fd,max(fd4, fd6)); + // spin_lock(&kcom_nodes_lock); + list_for_each_entry(node, &kcom_nodes, list) + n = max(node->fd, n); + // spin_unlock(&kcom_nodes_lock); + + + maxfds = n; + + kfree(sockets_fds_bitmap); + + size = FDS_BYTES(n); + sockets_fds_bitmap = kmalloc(6 * size, GFP_KERNEL); + if (!sockets_fds_bitmap) + return ENOMEM; + + sockets_fds.in = (unsigned long *) sockets_fds_bitmap; + sockets_fds.out = (unsigned long *) (sockets_fds_bitmap + size); + sockets_fds.ex = (unsigned long *) (sockets_fds_bitmap + 2*size); + sockets_fds.res_in = (unsigned long *) (sockets_fds_bitmap + 3*size); + sockets_fds.res_out = (unsigned long *) (sockets_fds_bitmap + 4*size); + sockets_fds.res_ex = (unsigned long *) (sockets_fds_bitmap + 5*size); + + return 0; + +} +EXPORT_SYMBOL_GPL(alloc_fd_bitmap); + +/** + * kcom_pkt_create + * + * Description: + * Allocate a kcom pkt from the slab. + * Initialize the pkt len,type and data ptr. + * If this is a new packet, increment the global msgid counter. + **/ +struct kcom_pkt *kcom_pkt_create(int len, int type, int ack, char *data) +{ + struct kcom_pkt *pkt; + + pkt=kmem_cache_alloc(kcom_pkt_cachep, SLAB_KERNEL); + if (pkt) { + pkt->len = len; + pkt->type = type; + + if (len > 0) + pkt->data=data; + else + pkt->data=NULL; + + // acks and responses don't get new a msgid + // FIXME: is this inc SMP safe? + if ((type & MSG_MASK) == PKT_NEW_MSG) + pkt->msgid = kcom_msgid++; + + return pkt; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(kcom_pkt_create); + +/** + * __kcom_node_find + * + * Description: + * Does the actual work of finding, if it exists, + * an existing node connection. + * The IP address is the determiner. + **/ +struct kcom_node *__kcom_node_find(struct sockaddr *saddr) +{ + struct kcom_node *tmp; + struct sockaddr_in *saddr_tmp; + struct sockaddr_in *saddr_in=(struct sockaddr_in *)saddr; + unsigned long int node_addr, find_addr; + + find_addr=saddr_in->sin_addr.s_addr; + + list_for_each_entry(tmp, &kcom_nodes, list) { + saddr_tmp=(struct sockaddr_in *)&tmp->addr; + node_addr=saddr_tmp->sin_addr.s_addr; + + if ((saddr_in->sin_family == saddr_tmp->sin_family) && + (find_addr == node_addr)) + return tmp; + } + return NULL; +} + + +/** + * kcom_node_find + * + * Description: + * calls __kcom_node_find + * , which searches for a node + **/ +struct kcom_node *kcom_node_find(struct sockaddr *saddr) +{ + task_t *p=current; + struct kcom_node *node; + struct sockaddr_in *addr_tmp; + unsigned int addr; + + addr_tmp=(struct sockaddr_in *)p->om.whereto; + addr=addr_tmp->sin_addr.s_addr; + // spin_lock(&kcom_nodes_lock); + node = __kcom_node_find(saddr); + // spin_unlock(&kcom_nodes_lock); + return node; +} +EXPORT_SYMBOL_GPL(kcom_node_find); + +/** + * kcom_node_add + * + * Description: + * adds a new node connection. + * signals kcomd that it needs to watch this node's socket. + * the file descriptor belonging to this socket is mapped in + * kcomd, but the function sock_map_fd. Due to a kernel security + * check file descriptors are not shared between kernel threads. + **/ +struct kcom_node *kcom_node_add(struct socket *sock) +{ + struct kcom_node *node; + + node=kmem_cache_alloc(kcom_node_cachep, SLAB_KERNEL); + if (!node) { + printk("Unable to allocate node space.\n"); + return NULL; //-ENOMEM; + } + INIT_LIST_HEAD(&node->list); + INIT_LIST_HEAD(&node->tasks); + node->sock=sock; + node->fd = 0; // kcomd will see this and assign a fd properly. + + /* + if (!sock->ops || !sock->ops->getname) + goto err; + + ret = sock->ops->getname + check if it's already in node list. + */ + + spin_lock(&kcom_nodes_lock); + list_add_tail(&node->list, &kcom_nodes); + spin_unlock(&kcom_nodes_lock); + + if (kcomd_task) + send_sig(SIGHUP,kcomd_task,0); + else { + printk("Unable to find kcomd daemon.\n"); + return NULL; + } + printk("leaving kcom_node_add\n"); + return node; + +} +EXPORT_SYMBOL_GPL(kcom_node_add); + +/** + * kcom_node_del + * + * Description: + * removes this node from the list of connected nodes. + * releases the corresponding socket and file descriptor. + **/ +int kcom_node_del(struct sockaddr *addr) +{ + struct kcom_node *node; + + /* remove the node from the list */ + spin_lock(&kcom_nodes_lock); + node = __kcom_node_find(addr); + if (!node) { + spin_unlock(&kcom_nodes_lock); + return -ENOENT; + } + list_del(&node->list); + spin_unlock(&kcom_nodes_lock); + + /* release and free structure */ + sys_close(node->fd); + sock_release(node->sock); + kfree(node); + return 0; +} + +/** + * set_sockopts + * + * Description: + * sets the socket options. TCP_NODELAY (send tcp packet immediately), + * keepalive intervals, retries, etc. + **/ +int set_sockopts(struct socket *sock) +{ + int val; + int ret; + char __user *pval; + mm_segment_t oldfs; + + oldfs = get_fs(); + set_fs(KERNEL_DS); + + pval = (char __user *) &val; + + val = 1; + ret = sock_setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, + pval, sizeof(val)); + if (ret) { + printk("unable to setsock SO_KEEPALIVE ERROR %d\n", ret); + return -1; + } + + /* FIXME: check on these, old COMM_MIGD */ + val = OPENMOSIX_CONNECTION_KEEPALIVE_INTERVAL; + ret = sock->ops->setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, + pval, sizeof(val)); + if (ret) { + printk("Unable to setsock TCP_KEEPINTVL ERROR %d\n", ret); + return -1; + } + + val = OPENMOSIX_CONNECTION_KEEPALIVE_MAXTRIES; + ret = sock->ops->setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, + pval, sizeof(val)); + if (ret) { + printk("unable to setsock TCP_KEEPCNT ERROR %d\n", ret); + return -1; + } + + val = OPENMOSIX_CONNECTION_KEEPALIVE_TOTAL; + ret = sock->ops->setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, + pval, sizeof(val)); + if (ret) { + printk("unable to setsock TCP_KEEPIDLE ERROR %d\n", ret); + return -1; + } + + val=1; + ret = sock->ops->setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, pval, sizeof(val)); + if (ret < 0) { + printk("Unable to setsockopt ERROR: %d\n", ret); + return -1; + } + set_fs(oldfs); + return 0; + +} + +/** + * create_connection + * + * Description: + * creates the network connection to other nodes and creates + * a node that holds this connection. Stores the corresponding + * IP address in the node as well. + **/ +struct kcom_node *create_connection(struct sockaddr *saddr) +{ + + struct socket *sock; + // int fd; + int ret; + int error; + DECLARE_WAITQUEUE(wait, current); + unsigned long timo=MAX_SCHEDULE_TIMEOUT; + + struct kcom_node *node; + + ret = sock_create(saddr->sa_family, SOCK_STREAM, IPPROTO_TCP, &sock); + if (ret < 0) { + printk("Unable to sock_create. ret=%d\n", ret); + return NULL; + } + + error = sock->ops->connect(sock, saddr, sizeof(struct sockaddr_in), O_NONBLOCK); + add_wait_queue(sock->sk->sk_sleep, &wait); + while (sock->state != SS_CONNECTED) { + set_current_state(TASK_INTERRUPTIBLE); + error = sock->ops->connect(sock, saddr, sizeof(struct sockaddr_in), O_NONBLOCK); + if (error != -EALREADY || (error = sock_error(sock->sk))) + break; + timo = schedule_timeout(timo); + if (timo <= 0) { + error = -EAGAIN; + break; + } + } + remove_wait_queue(sock->sk->sk_sleep, &wait); + set_current_state(TASK_RUNNING); + + if (error < 0) { + printk("Unable to create connection. Err %d\n", error); + return NULL; + } + + node = kcom_node_find(saddr); + if (!node) { + node = kcom_node_add(sock); + if (!node) { + printk("Unable to add node\n"); + return NULL; + } + memcpy(&node->addr, saddr, sizeof(*saddr)); + ret=set_sockopts(node->sock); + if (ret) { + printk("Unable to set socket options.\n"); + return NULL; + } + } else + printk("Connection already exists. Not creating new node.\n"); + + return node; + +} +EXPORT_SYMBOL_GPL(create_connection); + +/** + * kcom_task_create + * + * Description: + * creates the kcom task related to this process. + * initializes the linked lists for incoming and outgoing + * pkts. Also links this task to the corresponding node + * since only migrated(ing) processes need kcom tasks. + **/ +struct kcom_task *kcom_task_create(struct kcom_node *node, int pid) +{ + struct kcom_task *kctask; + task_t *p; + + kctask=kmem_cache_alloc(kcom_task_cachep, SLAB_KERNEL); + + if (kctask) { + if (pid==0) { // this only occurs when remote node is creating new proc. + kctask->rpid = 0; + kctask->hpid = pid; + } else { + // read_lock(&tasklist_lock); + p = find_task_by_pid(pid); + // read_unlock(&tasklist_lock); + if (p) { + if (task_test_dflags(p, DREMOTE)) { + kctask->rpid = pid; + kctask->hpid = 0; + } else { + kctask->hpid = pid; + kctask->rpid = 0; + } + } else { + printk("ERROR creating kcom task.\n"); + return NULL; + } + } + + kctask->node = node; + INIT_LIST_HEAD(&kctask->list); + INIT_LIST_HEAD(&kctask->out_packs); + INIT_LIST_HEAD(&kctask->in_packs); + spin_lock_init(&kctask->spinlock); + + list_add_tail(&kctask->list, &node->tasks); + } else + return NULL; + return kctask; +} +EXPORT_SYMBOL_GPL(kcom_task_create); + +/** + * kcom_task_delete + * + * Description: + * deletes the kcom task and frees the memory. + * Lookins that dflags to see if this is a process is a + * remote process corresponding to a migrated process or + * if its a 'home' process. + * This is needed since both process ID's are kept in the + * kcom task. + **/ +int kcom_task_delete(pid_t pid) +{ + struct kcom_node *tmp; + struct kcom_task *tmp2; + struct kcom_task *tsk; + + // Can't delete task until all pkts are sent. + tsk=kcom_task_find(pid); + // FIXME: SMP safety + while (!list_empty(&tsk->out_packs)) + schedule_timeout(HZ/1000); + + + list_for_each_entry(tmp, &kcom_nodes, list) + list_for_each_entry(tmp2, &tmp->tasks, list) + if (task_test_dflags(current, DREMOTE)) { + if (tmp2->rpid == pid) { + printk("Deleting remote kcom task %u.\n", pid); + list_del(&tmp2->list); + kfree(tmp2); + break; + } + } else { + if (tmp2->hpid == pid) { + printk("Deleting home kcom task %u.\n", pid); + list_del(&tmp2->list); + kfree(tmp2); + break; + } + } + return 0; +} + +/** + * __kcom_task_find + * + * Description: + * Searches all nodes for a specific task, by pid. + * Lookins that dflags to see if this is a process is a + * remote process corresponding to a migrated process or + * if its a 'home' process. + * This is needed since both process ID's are kept in the + * kcom task. + **/ +struct kcom_task *__kcom_task_find(pid_t pid, int where) +{ + struct kcom_node *tmp; + struct kcom_task *tmp2; + task_t *p; + + // read_lock(&tasklist_lock); + p = find_task_by_pid(pid); + // read_unlock(&tasklist_lock); + if (!p) { + printk("Unable to find pid %u\n", pid); + return NULL; + } + + if (where == 0) { + // printk("FUNCTION: kcom_task_find\n"); + list_for_each_entry(tmp, &kcom_nodes, list) + list_for_each_entry(tmp2, &tmp->tasks, list) + // One remote node, we're interested in rpid + // One home node, we're interested in hpid + if (task_test_dflags(p, DREMOTE)) { + // printk("kcom_task_find: dremote\n"); + if (tmp2->rpid == pid) + return tmp2; + } else { + // printk("kcom_task_find: ddeputy\n"); + if (tmp2->hpid == pid) + return tmp2; + } + } else if (where == 1) { // home + list_for_each_entry(tmp, &kcom_nodes, list) + list_for_each_entry(tmp2, &tmp->tasks, list) + if (tmp2->hpid == pid) + return tmp2; + } else if (where == 2) { // remote + list_for_each_entry(tmp, &kcom_nodes, list) + list_for_each_entry(tmp2, &tmp->tasks, list) + if (tmp2->rpid == pid) + return tmp2; + + } + // printk("leaving FUNCTION: kcom_task_find\n"); + return NULL; +} + +/** + * kcom_task_find + * + * Description: + * calls __kcom_task_find, specifically looking + * for a home pid. + **/ +struct kcom_task *kcom_home_task_find(pid_t pid) +{ + struct kcom_task *tmp; + + tmp = __kcom_task_find(pid, 1); + return tmp; + +} +EXPORT_SYMBOL_GPL(kcom_home_task_find); + +/** + * kcom_remote_task_find + * + * Description: + * calls __kcom_task_find, specifically looking + * for a remote pid. + **/ +struct kcom_task *kcom_remote_task_find(pid_t pid) +{ + struct kcom_task *tmp; + + tmp = __kcom_task_find(pid, 2); + return tmp; + +} +EXPORT_SYMBOL_GPL(kcom_remote_task_find); + + +/** + * kcom_task_find + * + * Description: + * calls __kcom_task_find, which looks + * at dflags to determine for itself if this is + * a home or remote pid. + **/ +struct kcom_task *kcom_task_find(pid_t pid) +{ + struct kcom_task *tmp; + + tmp = __kcom_task_find(pid, 0); + return tmp; +} +EXPORT_SYMBOL_GPL(kcom_task_find); + +/** + * kcom_task_send + * + * Description: + * Creates a packet to send and adds it to the task's outbound list. + * No acknowledgement or reply is expected. + **/ +int kcom_task_send(struct kcom_task *tsk, int type, int datasize, char *data, char *resp, unsigned long addr) +{ + // struct kcom_task *tsk; + struct kcom_pkt *pkt; + + // printk("kcom_task_send:\n"); + // tsk = kcom_task_find(pid); + if (!tsk) + return -ENODEV; + + /* put pkt in kcom_task */ + pkt = kcom_pkt_create(datasize, type, PKT_NEW_MSG, data); + if (!pkt) + return -1; + + if (!resp) + pkt->resp=data; + else + pkt->resp=resp; + + pkt->hpid=tsk->hpid; + pkt->rpid=tsk->rpid; + pkt->addr=addr; // used by vma_pages + + // spin_lock(&tsk->spinlock); + list_add_tail(&pkt->list, &tsk->out_packs); + // spin_unlock(&tsk->spinlock); + + return pkt->msgid; +} + +/** + * kcom_send + * + * Description: + * Tell this function what type of pkt, the data and where to send it and + * it finds the corresponding node, creating a new connection if necessary + * Finds the corresponding tsk, creating it if necessary. + * creates a packet to send and adds it to the task's outbound list. + * No acknowledgement or reply is expected. + **/ +int kcom_send(int type, int datasize, char *data, unsigned long addr, struct sockaddr_in *saddr) +{ + + struct kcom_node *node; + struct kcom_task *tsk; + task_t *p = current; + unsigned int msgid; + + node=kcom_node_find((struct sockaddr *)saddr); + if (node==NULL) { + printk("node not found, creating new connection.\n"); + node=create_connection((struct sockaddr *)saddr); + if (node==NULL) + return -1; + } + + tsk=kcom_task_find(p->pid); + if (tsk==NULL) { + printk("Task not found. creating new.\n"); + tsk=kcom_task_create(node, p->pid); + if (tsk==NULL) + return -1; + } + + msgid=kcom_task_send(tsk, type, datasize, data, NULL, addr); + + if (kcomd_task != NULL) + send_sig(SIGHUP,kcomd_task,0); + + return 0; +} +/** + * kcom_send_nack + * + * Description: + * Send an ack to the other node. This is the matching function for kcom_send_with_ack. + * An ack is the acknowledgement that the kcom pkt was received correctly. + **/ +int kcom_send_nack(task_t *p, struct kcom_pkt *recv_pkt) +{ + // task_t *kcomd_task; + int mig_flag; + int syscall_flag; + int node_flag; + struct kcom_pkt *send_pkt; + struct kcom_task *send_tsk; + + mig_flag=recv_pkt->type & MIG_MASK; + syscall_flag=recv_pkt->type & SYSCALL_MASK; + + send_tsk=kcom_task_find(p->pid); + + if (task_test_dflags(p, DREMOTE)) + node_flag = REM_FLG; + else + node_flag = DEP_FLG; + send_pkt=kcom_pkt_create(0, mig_flag | syscall_flag | PKT_NACK | node_flag, PKT_NACK, NULL); + + send_pkt->msgid=recv_pkt->msgid; // responses have same msg id as pkt they are responding to. + send_pkt->hpid=recv_pkt->hpid; + send_pkt->rpid=recv_pkt->rpid; + send_pkt->resp=recv_pkt->resp; + + // spin_lock(&send_tsk->spinlock); // done outside this function + list_add_tail(&send_pkt->list, &send_tsk->out_packs); + // spin_unlock(&send_tsk->spinlock); + + if (kcomd_task) + send_sig(SIGHUP,kcomd_task,0); + else { + printk("Unable to signal kcomd\n"); + return -1; + } + + return 0; +} +EXPORT_SYMBOL(kcom_send_nack); + + +/** + * kcom_send_ack + * + * Description: + * Send an ack to the other node. This is the matching function for kcom_send_with_ack. + * An ack is the acknowledgement that the kcom pkt was received correctly. + **/ +int kcom_send_ack(task_t *p, struct kcom_pkt *recv_pkt) +{ + // task_t *kcomd_task; + int mig_flag; + int syscall_flag; + int node_flag; + struct kcom_pkt *send_pkt; + struct kcom_task *send_tsk; + + mig_flag=recv_pkt->type & MIG_MASK; + syscall_flag=recv_pkt->type & SYSCALL_MASK; + + send_tsk=kcom_task_find(p->pid); + + if (task_test_dflags(p, DREMOTE)) + node_flag = REM_FLG; + else + node_flag = DEP_FLG; + send_pkt=kcom_pkt_create(0, mig_flag | syscall_flag | PKT_ACK | node_flag, PKT_ACK, NULL); + + send_pkt->msgid=recv_pkt->msgid; // responses have same msg id as pkt they are responding to. + send_pkt->hpid=recv_pkt->hpid; + send_pkt->rpid=recv_pkt->rpid; + send_pkt->resp=recv_pkt->resp; + + // spin_lock(&send_tsk->spinlock); // done outside this function + list_add_tail(&send_pkt->list, &send_tsk->out_packs); + // spin_unlock(&send_tsk->spinlock); + + if (kcomd_task) + send_sig(SIGHUP,kcomd_task,0); + else { + printk("Unable to signal kcomd\n"); + return -1; + } + + return 0; +} +EXPORT_SYMBOL(kcom_send_ack); + +/** + * kcom_send_resp + * + * Description: + * Send an response to the other node. This is the matching function for kcom_send_with_response. + * An response is both the acknowledgement that the kcom pkt was received correctly (or not) and + * the expected response data. + **/ +int kcom_send_resp(task_t *p, int len, char *buf, struct kcom_pkt *recv_pkt) +{ + int mig_flag; + int syscall_flag; + int node_flag; + struct kcom_pkt *send_pkt; + struct kcom_task *send_tsk; + + mig_flag=recv_pkt->type & MIG_MASK; + syscall_flag=recv_pkt->type & SYSCALL_MASK; + + send_tsk=kcom_task_find(p->pid); + + if (task_test_dflags(p, DREMOTE)) + node_flag = REM_FLG; + else + node_flag = DEP_FLG; + + send_pkt=kcom_pkt_create(len, mig_flag | syscall_flag | PKT_ACK | node_flag, PKT_ACK, buf); + + send_pkt->msgid=recv_pkt->msgid; + send_pkt->hpid=send_tsk->hpid; + send_pkt->rpid=send_tsk->rpid; + send_pkt->resp=recv_pkt->resp; + + list_add_tail(&send_pkt->list, &send_tsk->out_packs); + if (kcomd_task) { + printk("Signaling kcomd\n"); + send_sig(SIGHUP, kcomd_task, 0); + } else { + printk("Unable to signal kcomd\n"); + return -1; + } + return 0; + +} +EXPORT_SYMBOL(kcom_send_resp); + +/** + * wait_for_ack + * + * Description: + * This actually checks the task's incoming pkt list for the matching msgid. + * If the matching pkt is found, it is removed from the list and the function + * returns success, else returns failure. + **/ +int wait_for_ack(struct kcom_task *task, unsigned int msgid) +{ + struct kcom_pkt *pkt, *pkt_next; + + // spin_lock(&task->spinlock); + if (!list_empty(&task->in_packs)) { + list_for_each_entry_safe(pkt, pkt_next, &task->in_packs, list) { + if ((msgid==pkt->msgid) && ((pkt->type & MSG_MASK) == PKT_ACK)) { + list_del(&pkt->list); + kmem_cache_free(kcom_pkt_cachep, pkt); + + // FIXME: this doesn't belong here. + // init packet has rpid + if ((pkt->type & MIG_MASK) == MIG_INIT) + task->rpid=pkt->rpid; + + // spin_unlock(&task->spinlock); + + return 0; + } // FIXME: what about nacks? + + } + } + + // spin_unlock(&task->spinlock); + return -1; + +} + +/** + * wait_for_response + * + * Description: + * This actually checks the task's incoming pkt list for the matching msgid. + * If the matching pkt is found, it is removed from the list and the function + * returns success, else returns failure. + * FIXME: very similar to wait_for_ack, merge?? + **/ +int wait_for_response(struct kcom_task *task, unsigned int msgid) +{ + struct kcom_pkt *pkt, *pkt_next; + int i=-1; + + printk("wait_for_response...for msgid %u\n", msgid); + list_for_each_entry_safe(pkt, pkt_next, &task->in_packs, list) + // FIXME: check for resp or ack, too. + if (msgid==pkt->msgid) { + i=pkt->len; + list_del(&pkt->list); + kmem_cache_free(kcom_pkt_cachep, pkt); + printk("wait_for_response: i=%d, addr=%lu pkt->resp=%s\n", i, pkt->addr, pkt->resp); + } + return i; + +} + +/** + * kcom_send_with_ack + * + * Description: + * Same as kcom_send except this function waits until an (n)ack is received. + **/ +int kcom_send_with_ack(int type, int datasize, char *data, unsigned long addr, struct sockaddr_in *saddr) +{ + struct kcom_node *node; + struct kcom_task *tsk; + task_t *p = current; + unsigned int msgid; + + node=kcom_node_find((struct sockaddr *)saddr); + if (node==NULL) { + printk("Node not found, creating new connection.\n"); + node=create_connection((struct sockaddr *)saddr); + if (!node) { + printk("ERROR: Unable to create new connection.\n"); + return -1; + } + } + + tsk=kcom_task_find(p->pid); + if (tsk==NULL) { + printk("Task not found. creating new.\n"); + tsk=kcom_task_create(node, p->pid); + if (!tsk) { + printk("ERROR: Unable to create task.\n"); + return -1; + } + } + + // FIXME: what if tsk is deleted between kcom_task_send and wait_for_ack ? + msgid=kcom_task_send(tsk, type, datasize, data, NULL, addr); + + if (kcomd_task) + send_sig(SIGHUP,kcomd_task,0); + else { + printk("Unable to find kcomd daemon.\n"); + return -1; + } + + set_current_state(TASK_INTERRUPTIBLE); + while (wait_for_ack(tsk, msgid)!=0) { + schedule(); + set_current_state(TASK_INTERRUPTIBLE); + } + set_current_state(TASK_RUNNING); + printk("Done waiting. msgid %d received...\n", msgid); + + + return 0; +} + +/** + * kcom_send_with_response + * + * Description: + * Same as kcom_send except this function waits until an response is received. + **/ +int kcom_send_with_response(int type, int datasize, char *data, unsigned long addr, char *resp, struct sockaddr_in *saddr) +{ + struct kcom_node *node; + struct kcom_task *tsk; + task_t *p = current; + unsigned int msgid; + int i=-1; + + node=kcom_node_find((struct sockaddr *)saddr); + if (node==NULL) { + printk("node not found, creating new connection.\n"); + node=create_connection((struct sockaddr *)saddr); + if (node==NULL) { + return -1; + } + } + + tsk=kcom_task_find(p->pid); + if (!tsk) { + printk("Task not found. Creating new.\n"); + tsk=kcom_task_create(node, p->pid); + if (!tsk) { + printk("Unable to create task\n"); + return -1; + } + } + + msgid=kcom_task_send(tsk, type, datasize, data, resp, addr); + + if (kcomd_task) + send_sig(SIGHUP,kcomd_task,0); + else { + printk("Unable to find kcomd daemon.\n"); + return -1; + } + + set_current_state(TASK_INTERRUPTIBLE); +retry: + i=wait_for_response(tsk, msgid); + if (i < 0) { + set_current_state(TASK_INTERRUPTIBLE); // Not the correct packet. go back to sleep + schedule(); + goto retry; + } + printk("Done waiting. msgid %d received...\n", msgid); + + return i; +} Index: linux/include/hpc/kcom.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux/include/hpc/kcom.h 2006-11-02 22:51:51.000000000 +0100 @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2006 Matt Dew <[email protected]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 only. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _HPC_KCOM_H +#define _HPC_KCOM_H + +#include <linux/sched.h> +#include <net/sock.h> +#include <hpc/comm.h> + +#include <linux/in.h> + +#include <hpc/protocol.h> + +#define DAEMON_IP4_PORT 0xB55 // 2901 +#define DAEMON_IP6_PORT 0xB56 // 2902 + +/* PROTOTYPES */ +#ifdef _HPC_KCOMC_H + DEFINE_SPINLOCK(kcom_nodes_lock); + EXPORT_SYMBOL(kcom_nodes_lock); + + struct list_head kcom_nodes = LIST_HEAD_INIT(kcom_nodes); + EXPORT_SYMBOL(kcom_nodes); + + fd_set_bits sockets_fds; + EXPORT_SYMBOL(sockets_fds); + + char *sockets_fds_bitmap = NULL; + EXPORT_SYMBOL(sockets_fds_bitmap); + + int maxfds = -1; + EXPORT_SYMBOL(maxfds); + + struct socket *lsock4=NULL, *lsock6=NULL; + EXPORT_SYMBOL(lsock4); + EXPORT_SYMBOL(lsock6); + + int fd4, fd6; + EXPORT_SYMBOL(fd4); + EXPORT_SYMBOL(fd6); + + // pid_t kcom_pid; + // EXPORT_SYMBOL(kcom_pid); + + task_t *kcomd_task=NULL; + EXPORT_SYMBOL(kcomd_task); + + unsigned int kcom_msgid=0; + EXPORT_SYMBOL(kcom_msgid); + + kmem_cache_t *kcom_data_cachep; + EXPORT_SYMBOL(kcom_data_cachep); + + kmem_cache_t *kcom_pkt_cachep; + EXPORT_SYMBOL(kcom_pkt_cachep); + + kmem_cache_t *kcom_task_cachep; + EXPORT_SYMBOL(kcom_task_cachep); + + kmem_cache_t *kcom_node_cachep; + EXPORT_SYMBOL(kcom_node_cachep); + + kmem_cache_t *kcom_saddr_cachep; + EXPORT_SYMBOL(kcom_saddr_cachep); + + +#else /* _HPC_KCOMC_H */ + extern int maxfds; + extern spinlock_t kcom_nodes_lock; + extern struct list_head kcom_nodes; + + extern fd_set_bits sockets_fds; + extern char *sockets_fds_bitmap; + extern struct socket *lsock4; + extern struct socket *lsock6; + extern int fd4; + extern int fd6; + + //extern pid_t kcom_pid; + extern task_t *kcomd_task; + extern kmem_cache_t *kcom_data_cachep; + extern kmem_cache_t *kcom_pkt_cachep; + extern kmem_cache_t *kcom_task_cachep; + extern kmem_cache_t *kcom_node_cachep; + extern kmem_cache_t *kcom_saddr_cachep; +#endif /* _HPC_KCOMC_H */ + + +struct kcom_pkt +{ + pid_t hpid; /* home pid of the this process */ + pid_t rpid; /* remote pid of 'that' other node process */ + int len; /* len of data */ + int type; /* type of data */ + // int ack; /* new msg, ack or response */ + unsigned long addr; /* used by mm pages */ + unsigned int msgid; + struct list_head list; + char *data; /* ptr of data */ + char *resp; /* ptr of response */ +}; + +struct kcom_node +{ + int fd; /* fd to send packet */ + struct socket *sock; /* socket */ + struct sockaddr addr; /* addr of this node */ + spinlock_t tasks_lock; /* lock for the list */ + struct list_head tasks; /* list of task */ + struct list_head list; /* list of nodes */ + spinlock_t spinlock; +}; + +struct kcom_task +{ + pid_t hpid; /* pid of the home node process owning this struct */ + pid_t rpid; /* pid of remote node process */ + struct kcom_node *node; /* node of the process to send/recv */ + struct list_head list; /* list of process using some node */ + + struct list_head out_packs; + // struct kcom_pkt in_packs; + struct list_head in_packs; + spinlock_t spinlock; // FIXME: ?? two spinlocks? in_packs, out_packs +}; + +extern int kcom_send_nack(task_t *p, struct kcom_pkt *recv_pkt); +#endif /* _HPC_KCOM_H */