diff --git a/executer/kernel/mcctrl/control.c b/executer/kernel/mcctrl/control.c index b5f2af52..3261b26e 100644 --- a/executer/kernel/mcctrl/control.c +++ b/executer/kernel/mcctrl/control.c @@ -1214,6 +1214,7 @@ int mcexec_open_exec(ihk_os_t os, char * __user filename) INIT_LIST_HEAD(&ppd->wq_req_list); INIT_LIST_HEAD(&ppd->wq_list_exact); init_waitqueue_head(&ppd->wq_prepare); + init_waitqueue_head(&ppd->wq_procfs); spin_lock_init(&ppd->wq_list_lock); memset(&ppd->cpu_set, 0, sizeof(cpumask_t)); ppd->ikc_target_cpu = 0; diff --git a/executer/kernel/mcctrl/ikc.c b/executer/kernel/mcctrl/ikc.c index f8cf86f6..461a23be 100644 --- a/executer/kernel/mcctrl/ikc.c +++ b/executer/kernel/mcctrl/ikc.c @@ -80,7 +80,7 @@ static int syscall_packet_handler(struct ihk_ikc_channel_desc *c, break; case SCD_MSG_PROCFS_ANSWER: - procfs_answer(pisp->arg, pisp->err); + procfs_answer(usrdata, pisp->pid); break; case SCD_MSG_SEND_SIGNAL: @@ -288,6 +288,7 @@ int prepare_ikc_channels(ihk_os_t os) ihk_ikc_listen_port(os, &usrdata->listen_param); memcpy(&usrdata->listen_param2, &listen_param2, sizeof listen_param2); ihk_ikc_listen_port(os, &usrdata->listen_param2); + init_waitqueue_head(&usrdata->wq_procfs); for (i = 0; i < MCCTRL_PER_PROC_DATA_HASH_SIZE; ++i) { INIT_LIST_HEAD(&usrdata->per_proc_data_hash[i]); diff --git a/executer/kernel/mcctrl/mcctrl.h b/executer/kernel/mcctrl/mcctrl.h index 63020009..09aca82e 100644 --- a/executer/kernel/mcctrl/mcctrl.h +++ b/executer/kernel/mcctrl/mcctrl.h @@ -197,6 +197,7 @@ struct mcctrl_per_proc_data { struct list_head wq_list_exact; ihk_spinlock_t wq_list_lock; wait_queue_head_t wq_prepare; + wait_queue_head_t wq_procfs; struct list_head per_thread_data_hash[MCCTRL_PER_THREAD_DATA_HASH_SIZE]; rwlock_t per_thread_data_hash_lock[MCCTRL_PER_THREAD_DATA_HASH_SIZE]; @@ -283,7 +284,7 @@ struct mcctrl_usrdata { int job_pos; int mcctrl_dma_abort; unsigned long last_thread_exec; - + wait_queue_head_t wq_procfs; struct list_head per_proc_data_hash[MCCTRL_PER_PROC_DATA_HASH_SIZE]; rwlock_t per_proc_data_hash_lock[MCCTRL_PER_PROC_DATA_HASH_SIZE]; @@ -351,7 +352,7 @@ struct procfs_file { char fname[PROCFS_NAME_MAX]; /* procfs filename (request) */ }; -void procfs_answer(unsigned int arg, int err); +void procfs_answer(struct mcctrl_usrdata *ud, int pid); int procfsm_packet_handler(void *os, int msg, int pid, unsigned long arg); void add_tid_entry(int osnum, int pid, int tid); void add_pid_entry(int osnum, int pid); diff --git a/executer/kernel/mcctrl/procfs.c b/executer/kernel/mcctrl/procfs.c index bee5483c..98058a1d 100644 --- a/executer/kernel/mcctrl/procfs.c +++ b/executer/kernel/mcctrl/procfs.c @@ -59,7 +59,6 @@ static const struct procfs_entry base_entry_stuff[]; static const struct file_operations mckernel_forward_ro; static const struct file_operations mckernel_forward; -static DECLARE_WAIT_QUEUE_HEAD(procfsq); static ssize_t mckernel_procfs_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos); @@ -106,14 +105,28 @@ getpath(struct procfs_list_entry *e, char *buf, int bufsize) /** * \brief Process SCD_MSG_PROCFS_ANSWER message. * - * \param arg sent argument - * \param err error info (redundant) + * \param ud mcctrl_usrdata pointer + * \param pid PID of the requesting process */ -void -procfs_answer(unsigned int arg, int err) +void procfs_answer(struct mcctrl_usrdata *ud, int pid) { - dprintk("procfs: received SCD_MSG_PROCFS_ANSWER message(err = %d).\n", err); - wake_up_interruptible(&procfsq); + struct mcctrl_per_proc_data *ppd = NULL; + + if (pid > 0) { + ppd = mcctrl_get_per_proc_data(ud, pid); + + if (unlikely(!ppd)) { + kprintf("%s: ERROR: no per-process structure for PID %d\n", + __FUNCTION__, pid); + return; + } + } + + wake_up_all(pid > 0 ? &ppd->wq_procfs : &ud->wq_procfs); + + if (pid > 0) { + mcctrl_put_per_proc_data(ppd); + } } static struct procfs_list_entry * @@ -495,36 +508,84 @@ procfs_exit(int osnum) * This function conforms to the 2) way of fs/proc/generic.c * from linux-2.6.39.4. */ -static ssize_t -mckernel_procfs_read(struct file *file, char __user *buf, size_t nbytes, - loff_t *ppos) +static ssize_t __mckernel_procfs_read_write( + struct file *file, + char __user *buf, size_t nbytes, + loff_t *ppos, int read_write) { struct inode * inode = file->f_inode; char *kern_buffer = NULL; int order = 0; volatile struct procfs_read *r = NULL; struct ikc_scd_packet isp; - int ret; + int ret, osnum, pid, retw; unsigned long pbuf; unsigned long count = nbytes; #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) struct proc_dir_entry *dp = PDE(inode); struct procfs_list_entry *e = dp->data; -#else +#else struct procfs_list_entry *e = PDE_DATA(inode); -#endif +#endif loff_t offset = *ppos; char pathbuf[PROCFS_NAME_MAX]; - char *path; + char *path, *p; + ihk_os_t os = NULL; + struct mcctrl_usrdata *udp = NULL; + struct mcctrl_per_proc_data *ppd = NULL; - path = getpath(e, pathbuf, 256); - dprintk("mckernel_procfs_read: invoked for %s, offset: %lu, count: %d\n", - path, offset, count); - if (count <= 0 || offset < 0) { return 0; } - + + path = getpath(e, pathbuf, PROCFS_NAME_MAX); + dprintk("%s: invoked for %s, offset: %lu, count: %lu\n", + __FUNCTION__, path, + (unsigned long)offset, count); + + /* Verify OS number */ + ret = sscanf(path, "mcos%d/", &osnum); + if (ret != 1) { + printk("%s: error: couldn't determine OS number\n", __FUNCTION__); + return -EINVAL; + } + + if (osnum != e->osnum) { + printk("%s: error: OS numbers don't match\n", __FUNCTION__); + return -EINVAL; + } + + /* Is this request for a specific process? */ + p = strchr(path, '/') + 1; + ret = sscanf(p, "%d/", &pid); + if (ret != 1) { + pid = -1; + } + + os = osnum_to_os(osnum); + if (!os) { + printk("%s: error: no IHK OS data found for OS %d\n", + __FUNCTION__, osnum); + return -EINVAL; + } + + udp = ihk_host_os_get_usrdata(os); + if (!udp) { + printk("%s: error: no MCCTRL data found for OS %d\n", + __FUNCTION__, osnum); + return -EINVAL; + } + + if (pid > 0) { + ppd = mcctrl_get_per_proc_data(udp, pid); + + if (unlikely(!ppd)) { + printk("%s: error: no per-process structure for PID %d", + __FUNCTION__, pid); + return -EINVAL; + } + } + while ((1 << order) < count) ++order; if (order > 12) { order -= 12; @@ -536,10 +597,11 @@ mckernel_procfs_read(struct file *file, char __user *buf, size_t nbytes, /* NOTE: we need physically contigous memory to pass through IKC */ kern_buffer = (char *)__get_free_pages(GFP_KERNEL, order); if (!kern_buffer) { - printk("mckernel_procfs_read(): ERROR: allocating kernel buffer\n"); - return -ENOMEM; + printk("%s: ERROR: allocating kernel buffer\n", __FUNCTION__); + ret = -ENOMEM; + goto out; } - + pbuf = virt_to_phys(kern_buffer); r = kmalloc(sizeof(struct procfs_read), GFP_KERNEL); @@ -553,152 +615,96 @@ mckernel_procfs_read(struct file *file, char __user *buf, size_t nbytes, r->status = 0; r->offset = offset; r->count = count; - r->readwrite = 0; + r->readwrite = read_write; strncpy((char *)r->fname, path, PROCFS_NAME_MAX); isp.msg = SCD_MSG_PROCFS_REQUEST; isp.ref = 0; isp.arg = virt_to_phys(r); - - ret = mcctrl_ikc_send(osnum_to_os(e->osnum), 0, &isp); - + isp.pid = pid; + + ret = mcctrl_ikc_send(osnum_to_os(e->osnum), + (pid > 0) ? ppd->ikc_target_cpu : 0, &isp); + if (ret < 0) { goto out; /* error */ } - + /* Wait for a reply. */ ret = -EIO; /* default exit code */ - dprintk("now wait for a relpy\n"); - - /* Wait for the status field of the procfs_read structure set ready. */ - if (wait_event_interruptible_timeout(procfsq, r->status != 0, HZ) == 0) { - kprintf("ERROR: mckernel_procfs_read: timeout (1 sec).\n"); + dprintk("%s: waiting for reply\n", __FUNCTION__); + +retry_wait: + /* Wait for the status field of the procfs_read structure, + * wait on per-process or OS specific data depending on + * who the request is for. + */ + if (pid > 0) { + retw = wait_event_interruptible_timeout(ppd->wq_procfs, + r->status != 0, HZ); + } + else { + retw = wait_event_interruptible_timeout(udp->wq_procfs, + r->status != 0, HZ); + } + + /* Timeout? */ + if (retw == 0 && r->status == 0) { + printk("%s: error: timeout (1 sec)\n", __FUNCTION__); goto out; } - - /* Wake up and check the result. */ - dprintk("mckernel_procfs_read: woke up. ret: %d, eof: %d\n", r->ret, r->eof); - - if (r->ret > 0) { - if (copy_to_user(buf, kern_buffer, r->ret)) { - kprintf("ERROR: mckernel_procfs_read: copy_to_user failed.\n"); - ret = -EFAULT; - goto out; - } + /* Interrupted? */ + else if (retw == -ERESTARTSYS) { + ret = -ERESTART; + goto out; + } + /* Were we woken up by a reply to another procfs request? */ + else if (r->status == 0) { + /* TODO: r->status is not set atomically, we could be woken + * up with status == 0 and it could change to 1 while in this + * code, we could potentially miss the wake_up()... + */ + printk("%s: stale wake-up, retrying\n", __FUNCTION__); + goto retry_wait; + } + /* Wake up and check the result. */ + dprintk("%s: woke up. ret: %d, eof: %d\n", + __FUNCTION__, r->ret, r->eof); + + if (r->ret > 0) { + if (read_write == 0) { + if (copy_to_user(buf, kern_buffer, r->ret)) { + printk("%s: ERROR: copy_to_user failed.\n", __FUNCTION__); + ret = -EFAULT; + goto out; + } + } *ppos += r->ret; } ret = r->ret; out: - if(kern_buffer) + if (ppd) + mcctrl_put_per_proc_data(ppd); + if (kern_buffer) free_pages((uintptr_t)kern_buffer, order); - if(r) + if (r) kfree((void *)r); - + return ret; } -static ssize_t -mckernel_procfs_write(struct file *file, const char __user *buf, size_t nbytes, - loff_t *ppos) +static ssize_t mckernel_procfs_read(struct file *file, + char __user *buf, size_t nbytes, loff_t *ppos) { - struct inode * inode = file->f_inode; - char *kern_buffer = NULL; - int order = 0; - volatile struct procfs_read *r = NULL; - struct ikc_scd_packet isp; - int ret; - unsigned long pbuf; - unsigned long count = nbytes; -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) - struct proc_dir_entry *dp = PDE(inode); - struct procfs_list_entry *e = dp->data; -#else - struct procfs_list_entry *e = PDE_DATA(inode); -#endif - loff_t offset = *ppos; - char pathbuf[PROCFS_NAME_MAX]; - char *path; + return __mckernel_procfs_read_write(file, buf, nbytes, ppos, 0); +} - path = getpath(e, pathbuf, 256); - dprintk("mckernel_procfs_read: invoked for %s, offset: %lu, count: %d\n", - path, offset, count); - - if (count <= 0 || offset < 0) { - return 0; - } - - while ((1 << order) < count) ++order; - if (order > 12) { - order -= 12; - } - else { - order = 1; - } - - /* NOTE: we need physically contigous memory to pass through IKC */ - kern_buffer = (char *)__get_free_pages(GFP_KERNEL, order); - if (!kern_buffer) { - printk("mckernel_procfs_read(): ERROR: allocating kernel buffer\n"); - return -ENOMEM; - } - if (copy_from_user(kern_buffer, buf, nbytes)) { - ret = -EFAULT; - goto out; - } - - pbuf = virt_to_phys(kern_buffer); - - r = kmalloc(sizeof(struct procfs_read), GFP_KERNEL); - if (r == NULL) { - ret = -ENOMEM; - goto out; - } - dprintk("offset: %lx, count: %d, cpu: %d\n", offset, count, e->cpu); - - r->pbuf = pbuf; - r->eof = 0; - r->ret = -EIO; /* default */ - r->status = 0; - r->offset = offset; - r->count = count; - r->readwrite = 1; - strncpy((char *)r->fname, path, PROCFS_NAME_MAX); - isp.msg = SCD_MSG_PROCFS_REQUEST; - isp.ref = 0; - isp.arg = virt_to_phys(r); - - ret = mcctrl_ikc_send(osnum_to_os(e->osnum), 0, &isp); - - if (ret < 0) { - goto out; /* error */ - } - - /* Wait for a reply. */ - ret = -EIO; /* default exit code */ - dprintk("now wait for a relpy\n"); - - /* Wait for the status field of the procfs_read structure set ready. */ - if (wait_event_interruptible_timeout(procfsq, r->status != 0, HZ) == 0) { - kprintf("ERROR: mckernel_procfs_read: timeout (1 sec).\n"); - goto out; - } - - /* Wake up and check the result. */ - dprintk("mckernel_procfs_read: woke up. ret: %d, eof: %d\n", r->ret, r->eof); - - if (r->ret > 0) { - *ppos += r->ret; - } - ret = r->ret; - -out: - if(kern_buffer) - free_pages((uintptr_t)kern_buffer, order); - if(r) - kfree((void *)r); - - return ret; +static ssize_t mckernel_procfs_write(struct file *file, + const char __user *buf, size_t nbytes, loff_t *ppos) +{ + return __mckernel_procfs_read_write(file, + (char __user *)buf, nbytes, ppos, 1); } static loff_t diff --git a/kernel/host.c b/kernel/host.c index e2a6ad70..c1092026 100644 --- a/kernel/host.c +++ b/kernel/host.c @@ -532,7 +532,7 @@ static void syscall_channel_send(struct ihk_ikc_channel_desc *c, } extern unsigned long do_kill(struct thread *, int, int, int, struct siginfo *, int ptracecont); -extern void process_procfs_request(unsigned long rarg); +extern void process_procfs_request(struct ikc_scd_packet *rpacket); extern void terminate_host(int pid); extern void debug_log(long); @@ -640,7 +640,7 @@ static int syscall_packet_handler(struct ihk_ikc_channel_desc *c, break; case SCD_MSG_PROCFS_REQUEST: - process_procfs_request(packet->arg); + process_procfs_request(packet); ret = 0; break; diff --git a/kernel/procfs.c b/kernel/procfs.c index f5ad271c..133edc89 100644 --- a/kernel/procfs.c +++ b/kernel/procfs.c @@ -76,11 +76,11 @@ procfs_delete_thread(struct thread *thread) * * \param rarg returned argument */ -void -process_procfs_request(unsigned long rarg) +void process_procfs_request(struct ikc_scd_packet *rpacket) { + unsigned long rarg = rpacket->arg; unsigned long parg, pbuf; - struct thread *thread = NULL; + struct thread *thread = NULL; struct process *proc = NULL; struct process_vm *vm = NULL; struct procfs_read *r; @@ -633,6 +633,7 @@ dataunavail: packet.msg = SCD_MSG_PROCFS_ANSWER; packet.arg = rarg; + packet.pid = rpacket->pid; ret = ihk_ikc_send(syscall_channel, &packet, 0); if (ret < 0) {