diff --git a/executer/kernel/ikc.c b/executer/kernel/ikc.c index 3da13a9e..f438f10b 100644 --- a/executer/kernel/ikc.c +++ b/executer/kernel/ikc.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "mcctrl.h" #ifdef ATTACHED_MIC #include @@ -39,21 +40,31 @@ //struct mcctrl_channel *channels; -DECLARE_WAIT_QUEUE_HEAD(procfs) - void mcexec_prepare_ack(ihk_os_t os, unsigned long arg, int err); static void mcctrl_ikc_init(ihk_os_t os, int cpu, unsigned long rphys, struct ihk_ikc_channel_desc *c); int mcexec_syscall(struct mcctrl_channel *c, int pid, unsigned long arg); +static DECLARE_WAIT_QUEUE_HEAD(procfsq); +static unsigned long procfsq_channel; + int mckernel_procfs_read(char *buffer, char **start, off_t offset, int count, int *peof, void *dat); /* A private data for the procfs driver. */ struct procfs_data { - int os; + ihk_os_t os; + int osnum; + int pid; int cpu; char fname[PROCFS_NAME_MAX]; -} +}; + +struct procfs_list_entry { + struct list_head list; + struct procfs_data *data; +}; + +LIST_HEAD(procfs_file_list); static int syscall_packet_handler(struct ihk_ikc_channel_desc *c, void *__packet, void *__os) @@ -78,18 +89,78 @@ static int syscall_packet_handler(struct ihk_ikc_channel_desc *c, mcexec_syscall(usrdata->channels + pisp->ref, pisp->pid, pisp->arg); break; case SCD_MSG_PROCFS_CREATE: - /* create procfs entry */ - /* register callback function */ - /* xxx */ + { + struct procfs_data *d; + unsigned long parg; + struct procfs_file *f; + struct proc_dir_entry *entry; + struct procfs_list_entry *e; + int mode; + ihk_device_t dev = ihk_os_to_dev(__os); + + d = kmalloc(sizeof(struct procfs_data), GFP_KERNEL); + if (d == NULL) { + kprintf("ERROR: not enough memory to create PROCFS entry.\n"); + } + d->osnum = pisp->osnum; + d->os = __os; + d->cpu = pisp->ref; + d->pid = pisp->pid; + + parg = ihk_device_map_memory(dev, pisp->arg, sizeof(struct procfs_file)); + f = ihk_device_map_virtual(dev, parg, sizeof(struct procfs_file), NULL, 0); + strncpy(d->fname, f->fname, PROCFS_NAME_MAX); + mode = f->mode; + f->status = 1; /* done */ + ihk_device_unmap_virtual(dev, f, sizeof(struct procfs_file)); + ihk_device_unmap_memory(dev, parg, sizeof(struct procfs_file)); + + entry = create_proc_entry(d->fname, mode, NULL); + if (entry == NULL) { + kprintf("ERROR: cannot create a PROCFS entry.\n"); + kfree(d); + goto quit; + } + entry->data = d; + entry->read_proc = mckernel_procfs_read; + + e = kmalloc(sizeof(struct procfs_list_entry), GFP_KERNEL); + if (e == NULL) { + kprintf("ERROR: not enough memory to create PROCFS entry.\n"); + kfree(d); + goto quit; + } + e->data = d; + list_add(&(e->list), &procfs_file_list); + } + quit: break; case SCD_MSG_PROCFS_DELETE: - /* deregister callback function */ - /* delete procfs entry */ - /* xxx */ + { + ihk_device_t dev = ihk_os_to_dev(__os); + unsigned long parg; + struct procfs_file *f; + struct procfs_list_entry *e; + + parg = ihk_device_map_memory(dev, pisp->arg, sizeof(struct procfs_file)); + f = ihk_device_map_virtual(dev, parg, sizeof(struct procfs_file), NULL, 0); + list_for_each_entry(e, &procfs_file_list, list) { + if (strncmp(e->data->fname, f->fname, PROCFS_NAME_MAX) == 0) { + list_del(&e->list); + kfree(e->data); + kfree(e); + break; + } + } + remove_proc_entry(f->fname, NULL); + ihk_device_unmap_virtual(dev, f, sizeof(struct procfs_file)); + ihk_device_unmap_memory(dev, parg, sizeof(struct procfs_file)); + + } break; case SCD_MSG_PROCFS_ANSWER: - /* wakeup processing thread */ - /* xxx */ + procfsq_channel = pisp->arg; + wake_up(&procfsq); break; } @@ -386,29 +457,56 @@ void destroy_ikc_channels(ihk_os_t os) * from linux-2.6.39.4. */ +static void *channel; + int mckernel_procfs_read(char *buffer, char **start, off_t offset, int count, int *peof, void *dat) { struct procfs_data *data = dat; struct procfs_read *r; struct ikc_scd_packet isp; + int ret; + unsigned long pbuf; - r = kmalloc(sizeof(struct procfs_read)); - if (r == NULL) { - /* what is the proper way to error? */ - return -1; + if (count <= 0 || dat == NULL) { + return 0; } - r->pbuf = virt_to_phys(buffer); + + pbuf = virt_to_phys(buffer); + if (pbuf / PAGE_SIZE != (pbuf + count - 1) / PAGE_SIZE) { + /* Truncate the read count upto the nearest page boundary */ + count = ((pbuf + count - 1) / PAGE_SIZE) * PAGE_SIZE - pbuf; + } + r = kmalloc(sizeof(struct procfs_read), GFP_KERNEL); + if (r == NULL) { + return -ENOMEM; + } +retry: + r->pbuf = pbuf; + r->eof = 0; + r->ret = 0; r->offset = offset; r->count = count; - strncpy(r->fname, dat->fname, PROCFS_NAME_MAX); - + strncpy(r->fname, data->fname, PROCFS_NAME_MAX); isp.msg = SCD_MSG_PROCFS_REQUEST; - isp.ref = dat->cpu; + isp.ref = data->cpu; isp.arg = virt_to_phys(r); - - /* send request to the McKernel and sleep */ - /* wake up and return the result */ - - return 0; + mcctrl_ikc_send(data->os, data->cpu, &isp); + channel = NULL; + /* Wait for a reply. */ + wait_event_interruptible(procfsq, procfsq_channel == virt_to_phys(r)); + /* Wake up and check the result. */ + if ((r->ret == 0) && (r->eof != 1)) { + /* A miss-hit has occurred (caused by migration e.g.). + * We simply retry the query. + */ + goto retry; + } + if (r->eof == 1) { + *peof = 1; + } + ret = r->ret; + kfree(r); + + return ret; } diff --git a/executer/kernel/mcctrl.h b/executer/kernel/mcctrl.h index 2ac2822d..21f8ad6c 100644 --- a/executer/kernel/mcctrl.h +++ b/executer/kernel/mcctrl.h @@ -68,6 +68,7 @@ struct coretable { struct ikc_scd_packet { int msg; int ref; + int osnum; int pid; int err; unsigned long arg; @@ -157,13 +158,21 @@ int deregister_peer_channel(struct mcctrl_usrdata *ud, void *key, struct mcctrl_ struct mcctrl_channel *get_peer_channel(struct mcctrl_usrdata *ud, void *key); int __do_in_kernel_syscall(ihk_os_t os, struct mcctrl_channel *c, struct syscall_request *sc); +#define PROCFS_NAME_MAX 1000 + struct procfs_read { - unsigned long int pbuf; /* physical address of the host buffer (request) */ - int offset; /* offset to read (request) */ + unsigned long pbuf; /* physical address of the host buffer (request) */ + unsigned long offset; /* offset to read (request) */ int count; /* bytes to read (request) */ int eof; /* if eof is detected, 1 otherwise 0. (answer)*/ - int return; /* read bytes (answer) */ + int ret; /* read bytes (answer) */ char fname[PROCFS_NAME_MAX]; /* procfs filename (request) */ -} +}; + +struct procfs_file { + int status; /* status of processing (answer) */ + int mode; /* file mode (request) */ + char fname[PROCFS_NAME_MAX]; /* procfs filename (request) */ +}; #endif diff --git a/kernel/Makefile.build b/kernel/Makefile.build index 49e40193..7c74905c 100644 --- a/kernel/Makefile.build +++ b/kernel/Makefile.build @@ -1,7 +1,7 @@ IHKDIR=$(IHKBASE)/$(TARGETDIR) OBJS = init.o mem.o debug.o mikc.o listeners.o ap.o syscall.o cls.o host.o OBJS += process.o copy.o waitq.o futex.o timer.o plist.o fileobj.o shmobj.o -OBJS += zeroobj.o +OBJS += zeroobj.o procfs.o DEPSRCS=$(wildcard $(SRC)/*.c) CFLAGS += -I$(SRC)/include -mcmodel=kernel -D__KERNEL__ diff --git a/kernel/host.c b/kernel/host.c index 713a02b8..35840d38 100644 --- a/kernel/host.c +++ b/kernel/host.c @@ -416,6 +416,7 @@ static int process_msg_prepare_process(unsigned long rphys) ihk_mc_unmap_virtual(p, npages, 1); ihk_mc_unmap_memory(NULL, phys, sz); flush_tlb(); + return 0; err: ihk_mc_free(pn); @@ -499,6 +500,8 @@ static void syscall_channel_send(struct ihk_ikc_channel_desc *c, extern unsigned long do_kill(int, int, int); extern void settid(struct process *proc, int mode, int newcpuid, int oldcpuid); +extern void process_procfs_request(unsigned long rarg); + static int syscall_packet_handler(struct ihk_ikc_channel_desc *c, void *__packet, void *ihk_os) { @@ -541,6 +544,9 @@ static int syscall_packet_handler(struct ihk_ikc_channel_desc *c, rc = do_kill((int)packet->pid, (int)(packet->arg >> 32), packet->arg & 0x00000000ffffffffL); kprintf("SCD_MSG_SEND_SIGNAL: %lx, rc=%d\n", packet->arg, rc); return 0; + case SCD_MSG_PROCFS_REQUEST: + process_procfs_request(packet->arg); + return 0; } return 0; } diff --git a/kernel/include/syscall.h b/kernel/include/syscall.h index d04d9a90..085a3088 100644 --- a/kernel/include/syscall.h +++ b/kernel/include/syscall.h @@ -36,6 +36,11 @@ #define SCD_MSG_SYSCALL_ONESIDE 0x4 #define SCD_MSG_SEND_SIGNAL 0x8 +#define SCD_MSG_PROCFS_CREATE 0x10 +#define SCD_MSG_PROCFS_DELETE 0x11 +#define SCD_MSG_PROCFS_REQUEST 0x12 +#define SCD_MSG_PROCFS_ANSWER 0x13 + #define ARCH_SET_GS 0x1001 #define ARCH_SET_FS 0x1002 #define ARCH_GET_FS 0x1003 @@ -87,6 +92,7 @@ struct user_desc { struct ikc_scd_packet { int msg; int ref; + int osnum; int pid; int err; unsigned long arg; @@ -231,4 +237,26 @@ struct coretable { /* table entry for a core chunk */ unsigned long addr; /* physical addr of the chunk */ }; +void create_proc_procfs_files(int pid, int cpuid); +void delete_proc_procfs_files(int pid); +void create_os_procfs_files(void); +void delete_os_procfs_files(void); + +#define PROCFS_NAME_MAX 1000 + +struct procfs_read { + unsigned long pbuf; /* physical address of the host buffer (request) */ + unsigned long offset; /* offset to read (request) */ + int count; /* bytes to read (request) */ + int eof; /* if eof is detected, 1 otherwise 0. (answer)*/ + int ret; /* read bytes (answer) */ + char fname[PROCFS_NAME_MAX]; /* procfs filename (request) */ +}; + +struct procfs_file { + int status; /* status of processing (answer) */ + int mode; /* file mode (request) */ + char fname[PROCFS_NAME_MAX]; /* procfs filename (request) */ +}; + #endif diff --git a/kernel/init.c b/kernel/init.c index 6f31113c..4ee08b82 100644 --- a/kernel/init.c +++ b/kernel/init.c @@ -43,6 +43,7 @@ #define dkprintf(...) #endif +int osnum = 0; extern struct ihk_kmsg_buf kmsg_buf; @@ -133,6 +134,16 @@ void pc_init(void) APT_TYPE_STALL, APT_TYPE_CYCLE }, // not updated for KNC }; + p = find_command_line("osnum="); + if (p != NULL) { + while (('0' <= *p) && (*p <= '9')) { + osnum *= 10; + osnum += *p++ - '0'; + } + } + kprintf("osnum: %d\n"); + + if (!(p = find_command_line("perfctr"))) { dkprintf("perfctr not initialized.\n"); return; diff --git a/kernel/process.c b/kernel/process.c index 39605b62..aa41446d 100644 --- a/kernel/process.c +++ b/kernel/process.c @@ -1661,6 +1661,8 @@ void destroy_process(struct process *proc) struct sig_pending *pending; struct sig_pending *next; + delete_proc_procfs_files(proc->pid); + if (proc->vm) { cpu_clear(proc->cpu_id, &proc->vm->cpu_set, &proc->vm->cpu_set_lock); } @@ -2034,6 +2036,8 @@ void runq_add_proc(struct process *proc, int cpu_id) __runq_add_proc(proc, cpu_id); ihk_mc_spinlock_unlock(&(v->runq_lock), irqstate); + create_proc_procfs_files(proc->pid, cpu_id); + /* Kick scheduler */ if (cpu_id != ihk_mc_get_processor_id()) ihk_mc_interrupt_cpu( diff --git a/kernel/procfs.c b/kernel/procfs.c new file mode 100644 index 00000000..d1988170 --- /dev/null +++ b/kernel/procfs.c @@ -0,0 +1,175 @@ +/** + * \file procfs.c + * License details are found in the file LICENSE. + * \brief + * McKernel procfs + * \author Naoki Hamada \par + * Copyright (C) 2014 AXE, Inc. + */ +/* + * HISTORY: + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG_PRINT_PROCFS + +#ifdef DEBUG_PRINT_PROCFS +#define dkprintf kprintf +#else +#define dkprintf(...) +#endif + +extern int snprintf(char * buf, size_t size, const char *fmt, ...); +extern int sscanf(const char * buf, const char * fmt, ...); + +extern int osnum; + +void create_proc_procfs_files(int pid, int cpuid); +void delete_proc_procfs_files(int pid); +void create_os_procfs_files(void); +void delete_os_procfs_files(void); + +static void create_proc_procfs_file(int pid, char *fname, int mode, int cpuid); +static void delete_proc_procfs_file(int pid, char *fname); +static void operate_proc_procfs_file(int pid, char *fname, int msg, int mode, int cpuid); + +void create_proc_procfs_files(int pid, int cpuid) +{ + char fname[PROCFS_NAME_MAX]; + + snprintf(fname, PROCFS_NAME_MAX, "/proc/mcos%d/%d/mem", osnum, pid); + create_proc_procfs_file(pid, fname, 0400, cpuid); +} + +static void create_proc_procfs_file(int pid, char *fname, int mode, int cpuid) +{ + operate_proc_procfs_file(pid, fname, SCD_MSG_PROCFS_CREATE, mode, cpuid); +} + +void delete_proc_procfs_files(int pid) +{ + char fname[PROCFS_NAME_MAX]; + + snprintf(fname, PROCFS_NAME_MAX, "/proc/mcos%d/%d/mem", osnum, pid); + delete_proc_procfs_file(pid, fname); +} + +static void delete_proc_procfs_file(int pid, char *fname) +{ + operate_proc_procfs_file(pid, fname, SCD_MSG_PROCFS_DELETE, 0, 0); +} + +static void operate_proc_procfs_file(int pid, char *fname, int msg, int mode, int cpuid) +{ + struct ihk_ikc_channel_desc *syscall_channel; + struct ikc_scd_packet pckt; + struct procfs_file *f; + int ret; + + syscall_channel = get_cpu_local_var(0)->syscall_channel; + + f = kmalloc(sizeof(struct procfs_file), IHK_MC_AP_NOWAIT); + if (!f) { + kprintf("ERROR: not enough memory for dealing procfs file %s!", + fname); + return; + } + f->status = 0; + f->mode = mode; + strncpy(f->fname, fname, PROCFS_NAME_MAX); + pckt.arg = virt_to_phys(f); + pckt.msg = msg; + pckt.osnum = osnum; + pckt.ref = cpuid; + pckt.pid = pid; + pckt.err = 0; + + ret = ihk_ikc_send(syscall_channel, &pckt, 0); + if (ret < 0) { + kprintf("ERROR: sending IKC msg, ret: %d\n", ret); + } + + while (f->status != 1) { + cpu_pause(); + } + kfree(f); +} + +void process_procfs_request(unsigned long rarg) +{ + unsigned long parg, pbuf; + struct process *proc = cpu_local_var(current); + struct procfs_read *r; + struct ikc_scd_packet packet; + int rosnum, ret, pid, tid, ans = -ENOENT, eof = 0; + char *buf; + struct ihk_ikc_channel_desc *syscall_channel; + + syscall_channel = get_cpu_local_var(0)->syscall_channel; + + parg = ihk_mc_map_memory(NULL, rarg, sizeof(struct procfs_read)); + r = ihk_mc_map_virtual(parg, sizeof(struct procfs_read), + PTATTR_WRITABLE | PTATTR_ACTIVE); + + pbuf = ihk_mc_map_memory(NULL, r->pbuf, r->count); + buf = ihk_mc_map_virtual(pbuf, r->count, PTATTR_WRITABLE | PTATTR_ACTIVE); + + /* mcos0/PID/taks/PID/mem */ + ret = sscanf(r->fname, "mcos%d/%d/task/%d/mem", &rosnum, &pid, &tid); + if ((ret == 3) && (pid == tid) && (osnum == rosnum)) { + if (cpu_local_var(current)->pid != pid) { + /* A hit-miss caused by migration */ + ans = 0; + } else { + struct vm_range *range; + struct process_vm *vm = proc->vm; + ans = -EIO; /* default to an I/O error */ + list_for_each_entry(range, &vm->vm_range_list, list) { + if ((range->start <= r->offset) && + (r->offset <= range->end)) { + if (r->offset + r->count <= range->end) { + memcpy((void *) buf, (void *) range->start, r->count); + ans = r->count; + } else { + unsigned int remain; + remain = range->end - r->offset; + memcpy((void *) buf, (void *)range->start, remain); + ans = remain; + } + break; + } + } + } + goto skip; + } + +skip: + r->ret = ans; + r->eof = eof; + packet.msg = SCD_MSG_PROCFS_ANSWER; + packet.arg = rarg; + + ihk_mc_unmap_virtual(buf, r->count, 0); + ihk_mc_unmap_memory(NULL, pbuf, r->count); + + ihk_mc_unmap_virtual(r, sizeof(struct procfs_read), 0); + ihk_mc_unmap_memory(NULL, parg, sizeof(struct procfs_read)); + + ret = ihk_ikc_send(syscall_channel, &packet, 0); + if (ret < 0) { + kprintf("ERROR: sending IKC msg, ret: %d\n", ret); + } +}