|
|
|
|
@ -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,16 +508,17 @@ 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)
|
|
|
|
|
@ -515,16 +529,63 @@ mckernel_procfs_read(struct file *file, char __user *buf, size_t nbytes,
|
|
|
|
|
#endif
|
|
|
|
|
loff_t offset = *ppos;
|
|
|
|
|
char pathbuf[PROCFS_NAME_MAX];
|
|
|
|
|
char *path;
|
|
|
|
|
|
|
|
|
|
path = getpath(e, pathbuf, 256);
|
|
|
|
|
dprintk("mckernel_procfs_read: invoked for %s, offset: %lu, count: %d\n",
|
|
|
|
|
path, offset, count);
|
|
|
|
|
char *path, *p;
|
|
|
|
|
ihk_os_t os = NULL;
|
|
|
|
|
struct mcctrl_usrdata *udp = NULL;
|
|
|
|
|
struct mcctrl_per_proc_data *ppd = NULL;
|
|
|
|
|
|
|
|
|
|
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,8 +597,9 @@ 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);
|
|
|
|
|
@ -553,13 +615,15 @@ 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);
|
|
|
|
|
isp.pid = pid;
|
|
|
|
|
|
|
|
|
|
ret = mcctrl_ikc_send(osnum_to_os(e->osnum), 0, &isp);
|
|
|
|
|
ret = mcctrl_ikc_send(osnum_to_os(e->osnum),
|
|
|
|
|
(pid > 0) ? ppd->ikc_target_cpu : 0, &isp);
|
|
|
|
|
|
|
|
|
|
if (ret < 0) {
|
|
|
|
|
goto out; /* error */
|
|
|
|
|
@ -567,29 +631,61 @@ mckernel_procfs_read(struct file *file, char __user *buf, size_t nbytes,
|
|
|
|
|
|
|
|
|
|
/* Wait for a reply. */
|
|
|
|
|
ret = -EIO; /* default exit code */
|
|
|
|
|
dprintk("now wait for a relpy\n");
|
|
|
|
|
dprintk("%s: waiting for reply\n", __FUNCTION__);
|
|
|
|
|
|
|
|
|
|
/* 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");
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
/* 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("mckernel_procfs_read: woke up. ret: %d, eof: %d\n", r->ret, r->eof);
|
|
|
|
|
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)) {
|
|
|
|
|
kprintf("ERROR: mckernel_procfs_read: copy_to_user failed.\n");
|
|
|
|
|
printk("%s: ERROR: copy_to_user failed.\n", __FUNCTION__);
|
|
|
|
|
ret = -EFAULT;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
*ppos += r->ret;
|
|
|
|
|
}
|
|
|
|
|
ret = r->ret;
|
|
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
if (ppd)
|
|
|
|
|
mcctrl_put_per_proc_data(ppd);
|
|
|
|
|
if (kern_buffer)
|
|
|
|
|
free_pages((uintptr_t)kern_buffer, order);
|
|
|
|
|
if (r)
|
|
|
|
|
@ -598,107 +694,17 @@ out:
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
return __mckernel_procfs_read_write(file, buf, nbytes, ppos, 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
|
|
|
|
|
|