mcctrl pager: handle pagers more properly

the pagers are all destroyed when linux thinks there is no process left,
but there is no synchronisation with mcexec on that and some new process
might have spawned and started using these pagers in the meantime,
leading to weird crashes because an invalid pager was used.

The reason we're cleaning up pagers when no process is left is that
mcctrl does not handle pager_req_release is the linux-side process got
killed or died before the mckernel one for some reason, so:
 - move pager_req_release to a new __do_in_kernel_irq_syscall() helper
 - have free_all_process_memory_range not set MF_HOST_RELEASED on the
memobj
 - just in case, clean up everything like before on mcctrl shutdown
instead of when no process is left.

Change-Id: I53b8b9b81b1e5b807593850af17b5ea5e8471174
Refs: #1154
This commit is contained in:
Dominique Martinet
2018-07-31 08:34:24 +09:00
committed by Balazs Gerofi
parent 94d093f058
commit e531ee626e
5 changed files with 86 additions and 63 deletions

View File

@ -1133,6 +1133,17 @@ int mcexec_syscall(struct mcctrl_usrdata *ud, struct ikc_scd_packet *packet)
int pid = packet->pid;
unsigned long flags;
struct mcctrl_per_proc_data *ppd;
int ret;
/* Handle requests that do not need the proxy process right now */
ret = __do_in_kernel_irq_syscall(ud->os, packet);
if (ret != -ENOSYS) {
ihk_ikc_release_packet((struct ihk_ikc_free_packet *)packet,
(ud->ikc2linux[smp_processor_id()] ?
ud->ikc2linux[smp_processor_id()] :
ud->ikc2linux[0]));
return ret;
}
/* Get a reference to per-process structure */
ppd = mcctrl_get_per_proc_data(ud, pid);

View File

@ -177,6 +177,7 @@ int mcctrl_os_shutdown_notifier(int os_index)
mdelay(200);
}
pager_cleanup();
sysfsm_cleanup(os[os_index]);
free_topology_info(os[os_index]);
ihk_os_unregister_user_call_handlers(os[os_index], mcctrl_uc + os_index);

View File

@ -420,7 +420,9 @@ extern void (*mcctrl_zap_page_range)(struct vm_area_struct *vma,
/* syscall.c */
void pager_add_process(void);
void pager_remove_process(struct mcctrl_per_proc_data *ppd);
void pager_cleanup(void);
int __do_in_kernel_irq_syscall(ihk_os_t os, struct ikc_scd_packet *packet);
int __do_in_kernel_syscall(ihk_os_t os, struct ikc_scd_packet *packet);
int mcctrl_add_per_proc_data(struct mcctrl_usrdata *ud, int pid,
struct mcctrl_per_proc_data *ppd);

View File

@ -64,6 +64,7 @@
#endif
static long pager_call_irq(ihk_os_t os, struct syscall_request *req);
static long pager_call(ihk_os_t os, struct syscall_request *req);
#ifdef SC_DEBUG
@ -962,35 +963,28 @@ struct pager {
off_t map_off;
};
/*
* for linux v2.6.35 or prior
*/
#ifndef DEFINE_SEMAPHORE
#define DEFINE_SEMAPHORE(...) DECLARE_MUTEX(__VA_ARGS__)
#endif
static DEFINE_SEMAPHORE(pager_sem);
static DEFINE_SPINLOCK(pager_lock);
static struct list_head pager_list = LIST_HEAD_INIT(pager_list);
int pager_nr_processes = 0;
void pager_add_process(void)
{
int error;
error = down_interruptible(&pager_sem);
if (error) {
return;
}
unsigned long flags;
spin_lock_irqsave(&pager_lock, flags);
++pager_nr_processes;
up(&pager_sem);
spin_unlock_irqrestore(&pager_lock, flags);
}
void pager_remove_process(struct mcctrl_per_proc_data *ppd)
{
int error;
struct pager *pager_next, *pager;
unsigned long flags;
if (in_atomic() || in_interrupt()) {
printk("%s: WARNING: shouldn't be called in IRQ context..\n",
@ -1015,15 +1009,17 @@ void pager_remove_process(struct mcctrl_per_proc_data *ppd)
/* Clean up global pagers for regular file mappings if this
* was the last process */
error = down_interruptible(&pager_sem);
if (error) {
return;
}
spin_lock_irqsave(&pager_lock, flags);
--pager_nr_processes;
if (pager_nr_processes > 0) {
goto out;
}
spin_unlock_irqrestore(&pager_lock, flags);
}
void pager_cleanup(void)
{
unsigned long flags;
struct pager *pager_next, *pager;
spin_lock_irqsave(&pager_lock, flags);
list_for_each_entry_safe(pager, pager_next, &pager_list, list) {
list_del(&pager->list);
@ -1040,8 +1036,7 @@ void pager_remove_process(struct mcctrl_per_proc_data *ppd)
kfree(pager);
}
out:
up(&pager_sem);
spin_unlock_irqrestore(&pager_lock, flags);
}
struct pager_create_result {
@ -1108,6 +1103,7 @@ static int pager_req_create(ihk_os_t os, int fd, uintptr_t result_pa)
uintptr_t phys;
struct kstat st;
int mf_flags = 0;
unsigned long irqflags;
dprintk("pager_req_create(%d,%lx)\n", fd, (long)result_pa);
@ -1156,12 +1152,7 @@ static int pager_req_create(ihk_os_t os, int fd, uintptr_t result_pa)
}
for (;;) {
error = down_interruptible(&pager_sem);
if (error) {
error = -EINTR;
printk("pager_req_create(%d,%lx):signaled. %d\n", fd, (long)result_pa, error);
goto out;
}
spin_lock_irqsave(&pager_lock, irqflags);
list_for_each_entry(pager, &pager_list, list) {
if (pager->inode == inode) {
@ -1180,7 +1171,7 @@ static int pager_req_create(ihk_os_t os, int fd, uintptr_t result_pa)
{
char *pathbuf, *fullpath;
pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);
pathbuf = kmalloc(PATH_MAX, GFP_ATOMIC);
if (pathbuf) {
fullpath = d_path(&file->f_path, pathbuf, PATH_MAX);
if (!IS_ERR(fullpath)) {
@ -1206,7 +1197,7 @@ static int pager_req_create(ihk_os_t os, int fd, uintptr_t result_pa)
break;
}
up(&pager_sem);
spin_unlock_irqrestore(&pager_lock, irqflags);
newpager = kzalloc(sizeof(*newpager), GFP_ATOMIC);
if (!newpager) {
@ -1226,7 +1217,7 @@ found:
get_file(file);
pager->rofile = file;
}
up(&pager_sem);
spin_unlock_irqrestore(&pager_lock, irqflags);
phys = ihk_device_map_memory(dev, result_pa, sizeof(*resp));
resp = ihk_device_map_virtual(dev, phys, sizeof(*resp), NULL, 0);
@ -1271,14 +1262,11 @@ static int pager_req_release(ihk_os_t os, uintptr_t handle, int unref)
int error;
struct pager *p;
struct pager *free_pager = NULL;
unsigned long flags;
dprintk("pager_req_relase(%p,%lx,%d)\n", os, handle, unref);
error = down_interruptible(&pager_sem);
if (error) {
printk("pager_req_relase(%p,%lx,%d):signaled. %d\n", os, handle, unref, error);
goto out;
}
spin_lock_irqsave(&pager_lock, flags);
error = -EBADF;
list_for_each_entry(p, &pager_list, list) {
@ -1293,7 +1281,7 @@ static int pager_req_release(ihk_os_t os, uintptr_t handle, int unref)
}
}
up(&pager_sem);
spin_unlock_irqrestore(&pager_lock, flags);
if (error) {
printk("pager_req_relase(%p,%lx,%d):pager not found. %d\n", os, handle, unref, error);
@ -1325,15 +1313,11 @@ static int pager_req_read(ihk_os_t os, uintptr_t handle, off_t off, size_t size,
ihk_device_t dev = ihk_os_to_dev(os);
void *buf = NULL;
loff_t pos;
unsigned long flags;
dprintk("pager_req_read(%lx,%lx,%lx,%lx)\n", handle, off, size, rpa);
ss = down_interruptible(&pager_sem);
if (ss) {
pr_debug("%s(%lx,%lx,%lx,%lx): signaled. %ld\n",
__func__, handle, off, size, rpa, ss);
goto out;
}
spin_lock_irqsave(&pager_lock, flags);
list_for_each_entry(pager, &pager_list, list) {
if ((uintptr_t)pager == handle) {
@ -1342,7 +1326,7 @@ static int pager_req_read(ihk_os_t os, uintptr_t handle, off_t off, size_t size,
break;
}
}
up(&pager_sem);
spin_unlock_irqrestore(&pager_lock, flags);
if (!file) {
ss = -EBADF;
@ -1416,14 +1400,11 @@ static int pager_req_write(ihk_os_t os, uintptr_t handle, off_t off, size_t size
loff_t pos;
loff_t fsize;
size_t len;
unsigned long flags;
dprintk("pager_req_write(%lx,%lx,%lx,%lx)\n", handle, off, size, rpa);
ss = down_interruptible(&pager_sem);
if (ss) {
printk("pager_req_write(%lx,%lx,%lx,%lx): signaled. %ld\n", handle, off, size, rpa, ss);
goto out;
}
spin_lock_irqsave(&pager_lock, flags);
list_for_each_entry(pager, &pager_list, list) {
if ((uintptr_t)pager == handle) {
@ -1434,7 +1415,7 @@ static int pager_req_write(ihk_os_t os, uintptr_t handle, off_t off, size_t size
if (file) {
get_file(file);
}
up(&pager_sem);
spin_unlock_irqrestore(&pager_lock, flags);
if (!file) {
ss = -EBADF;
@ -1829,12 +1810,6 @@ full:
return cnt;
}
static long pager_call(ihk_os_t os, struct syscall_request *req)
{
long ret;
dprintk("pager_call(%#lx)\n", req->args[0]);
switch (req->args[0]) {
#define PAGER_REQ_CREATE 0x0001
#define PAGER_REQ_RELEASE 0x0002
#define PAGER_REQ_READ 0x0003
@ -1843,13 +1818,28 @@ static long pager_call(ihk_os_t os, struct syscall_request *req)
#define PAGER_REQ_PFN 0x0006
#define PAGER_REQ_UNMAP 0x0007
#define PAGER_REQ_MLOCK_LIST 0x0008
case PAGER_REQ_CREATE:
ret = pager_req_create(os, req->args[1], req->args[2]);
break;
static long pager_call_irq(ihk_os_t os, struct syscall_request *req)
{
long ret = -ENOSYS;
switch (req->args[0]) {
case PAGER_REQ_RELEASE:
ret = pager_req_release(os, req->args[1], req->args[2]);
break;
}
return ret;
}
static long pager_call(ihk_os_t os, struct syscall_request *req)
{
long ret;
dprintk("pager_call(%#lx)\n", req->args[0]);
switch (req->args[0]) {
case PAGER_REQ_CREATE:
ret = pager_req_create(os, req->args[1], req->args[2]);
break;
case PAGER_REQ_READ:
ret = pager_req_read(os, req->args[1], req->args[2], req->args[3], req->args[4]);
@ -1871,6 +1861,7 @@ static long pager_call(ihk_os_t os, struct syscall_request *req)
case PAGER_REQ_UNMAP:
ret = pager_req_unmap(os, req->args[1]);
break;
case PAGER_REQ_MLOCK_LIST:
ret = pager_req_mlock_list(os, (unsigned long) req->args[1],
(unsigned long) req->args[2],
@ -2138,6 +2129,27 @@ fail:
#define SCHED_CHECK_SAME_OWNER 0x01
#define SCHED_CHECK_ROOT 0x02
int __do_in_kernel_irq_syscall(ihk_os_t os, struct ikc_scd_packet *packet)
{
struct syscall_request *sc = &packet->req;
int ret;
switch (sc->number) {
case __NR_mmap:
ret = pager_call_irq(os, sc);
break;
default:
ret = -ENOSYS;
}
if (ret == -ENOSYS)
return -ENOSYS;
__return_syscall(os, packet, ret, 0);
return 0;
}
int __do_in_kernel_syscall(ihk_os_t os, struct ikc_scd_packet *packet)
{
struct syscall_request *sc = &packet->req;

View File

@ -2510,9 +2510,6 @@ free_all_process_memory_range(struct process_vm *vm)
range = rb_entry(node, struct vm_range, vm_rb_node);
next = rb_next(node);
if (range->memobj) {
range->memobj->flags |= MF_HOST_RELEASED;
}
error = free_process_memory_range(vm, range);
if (error) {
ekprintf("free_process_memory(%p):"