diff options
-rw-r--r-- | sys/compat/linuxkpi/common/include/linux/kthread.h | 11 | ||||
-rw-r--r-- | sys/compat/linuxkpi/common/include/linux/sched.h | 19 | ||||
-rw-r--r-- | sys/compat/linuxkpi/common/src/linux_compat.c | 83 |
3 files changed, 90 insertions, 23 deletions
diff --git a/sys/compat/linuxkpi/common/include/linux/kthread.h b/sys/compat/linuxkpi/common/include/linux/kthread.h index f85a3f40ac55..61cdc3b8060a 100644 --- a/sys/compat/linuxkpi/common/include/linux/kthread.h +++ b/sys/compat/linuxkpi/common/include/linux/kthread.h @@ -2,7 +2,7 @@ * Copyright (c) 2010 Isilon Systems, Inc. * Copyright (c) 2010 iX Systems, Inc. * Copyright (c) 2010 Panasas, Inc. - * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd. + * Copyright (c) 2013-2016 Mellanox Technologies, Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -45,15 +45,18 @@ static inline void linux_kthread_fn(void *arg) { struct task_struct *task; + struct thread *td = curthread; task = arg; - task_struct_set(curthread, task); + task_struct_fill(td, task); + task_struct_set(td, task); if (task->should_stop == 0) task->task_ret = task->task_fn(task->task_data); - PROC_LOCK(task->task_thread->td_proc); + PROC_LOCK(td->td_proc); task->should_stop = TASK_STOPPED; wakeup(task); - PROC_UNLOCK(task->task_thread->td_proc); + PROC_UNLOCK(td->td_proc); + task_struct_set(td, NULL); kthread_exit(); } diff --git a/sys/compat/linuxkpi/common/include/linux/sched.h b/sys/compat/linuxkpi/common/include/linux/sched.h index c2d66d7fa6dd..ca1effe88600 100644 --- a/sys/compat/linuxkpi/common/include/linux/sched.h +++ b/sys/compat/linuxkpi/common/include/linux/sched.h @@ -2,7 +2,7 @@ * Copyright (c) 2010 Isilon Systems, Inc. * Copyright (c) 2010 iX Systems, Inc. * Copyright (c) 2010 Panasas, Inc. - * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd. + * Copyright (c) 2013-2016 Mellanox Technologies, Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -50,10 +50,12 @@ #define TASK_STOPPED 2 /* - * A task_struct is only provided for those tasks created with kthread. - * Using these routines with threads not started via kthread will cause - * panics because no task_struct is allocated and td_retval[1] is - * overwritten by syscalls which kernel threads will not make use of. + * A task_struct is only provided for threads created by kthread() and + * file operation callbacks. + * + * Using these routines outside the above mentioned contexts will + * cause panics because no task_struct is assigned and td_retval[1] is + * overwritten by syscalls. */ struct task_struct { struct thread *task_thread; @@ -62,10 +64,17 @@ struct task_struct { int task_ret; int state; int should_stop; + pid_t pid; + const char *comm; }; #define current task_struct_get(curthread) #define task_struct_get(x) ((struct task_struct *)(uintptr_t)(x)->td_retval[1]) +#define task_struct_fill(x, y) do { \ + (y)->task_thread = (x); \ + (y)->comm = (x)->td_name; \ + (y)->pid = (x)->td_tid; \ +} while (0) #define task_struct_set(x, y) (x)->td_retval[1] = (uintptr_t)(y) /* ensure the task_struct pointer fits into the td_retval[1] field */ diff --git a/sys/compat/linuxkpi/common/src/linux_compat.c b/sys/compat/linuxkpi/common/src/linux_compat.c index 91a8032a67b8..a03063bc9f63 100644 --- a/sys/compat/linuxkpi/common/src/linux_compat.c +++ b/sys/compat/linuxkpi/common/src/linux_compat.c @@ -374,12 +374,31 @@ kobject_init_and_add(struct kobject *kobj, const struct kobj_type *ktype, } static void +linux_set_current(struct thread *td, struct task_struct *t) +{ + memset(t, 0, sizeof(*t)); + task_struct_fill(td, t); + task_struct_set(td, t); +} + +static void +linux_clear_current(struct thread *td) +{ + task_struct_set(td, NULL); +} + +static void linux_file_dtor(void *cdp) { struct linux_file *filp; + struct task_struct t; + struct thread *td; + td = curthread; filp = cdp; + linux_set_current(td, &t); filp->f_op->release(filp->f_vnode, filp); + linux_clear_current(td); vdrop(filp->f_vnode); kfree(filp); } @@ -389,10 +408,11 @@ linux_dev_open(struct cdev *dev, int oflags, int devtype, struct thread *td) { struct linux_cdev *ldev; struct linux_file *filp; + struct task_struct t; struct file *file; int error; - file = curthread->td_fpop; + file = td->td_fpop; ldev = dev->si_drv1; if (ldev == NULL) return (ENODEV); @@ -402,21 +422,22 @@ linux_dev_open(struct cdev *dev, int oflags, int devtype, struct thread *td) filp->f_flags = file->f_flag; vhold(file->f_vnode); filp->f_vnode = file->f_vnode; + linux_set_current(td, &t); if (filp->f_op->open) { error = -filp->f_op->open(file->f_vnode, filp); if (error) { kfree(filp); - return (error); + goto done; } } error = devfs_set_cdevpriv(filp, linux_file_dtor); if (error) { filp->f_op->release(file->f_vnode, filp); kfree(filp); - return (error); } - - return 0; +done: + linux_clear_current(td); + return (error); } static int @@ -427,7 +448,7 @@ linux_dev_close(struct cdev *dev, int fflag, int devtype, struct thread *td) struct file *file; int error; - file = curthread->td_fpop; + file = td->td_fpop; ldev = dev->si_drv1; if (ldev == NULL) return (0); @@ -446,16 +467,18 @@ linux_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, { struct linux_cdev *ldev; struct linux_file *filp; + struct task_struct t; struct file *file; int error; - file = curthread->td_fpop; + file = td->td_fpop; ldev = dev->si_drv1; if (ldev == NULL) return (0); if ((error = devfs_get_cdevpriv((void **)&filp)) != 0) return (error); filp->f_flags = file->f_flag; + linux_set_current(td, &t); /* * Linux does not have a generic ioctl copyin/copyout layer. All * linux ioctls must be converted to void ioctls which pass a @@ -467,6 +490,7 @@ linux_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, error = -filp->f_op->unlocked_ioctl(filp, cmd, (u_long)data); else error = ENOTTY; + linux_clear_current(td); return (error); } @@ -476,11 +500,14 @@ linux_dev_read(struct cdev *dev, struct uio *uio, int ioflag) { struct linux_cdev *ldev; struct linux_file *filp; + struct task_struct t; + struct thread *td; struct file *file; ssize_t bytes; int error; - file = curthread->td_fpop; + td = curthread; + file = td->td_fpop; ldev = dev->si_drv1; if (ldev == NULL) return (0); @@ -490,6 +517,7 @@ linux_dev_read(struct cdev *dev, struct uio *uio, int ioflag) /* XXX no support for I/O vectors currently */ if (uio->uio_iovcnt != 1) return (EOPNOTSUPP); + linux_set_current(td, &t); if (filp->f_op->read) { bytes = filp->f_op->read(filp, uio->uio_iov->iov_base, uio->uio_iov->iov_len, &uio->uio_offset); @@ -502,6 +530,7 @@ linux_dev_read(struct cdev *dev, struct uio *uio, int ioflag) error = -bytes; } else error = ENXIO; + linux_clear_current(td); return (error); } @@ -511,11 +540,14 @@ linux_dev_write(struct cdev *dev, struct uio *uio, int ioflag) { struct linux_cdev *ldev; struct linux_file *filp; + struct task_struct t; + struct thread *td; struct file *file; ssize_t bytes; int error; - file = curthread->td_fpop; + td = curthread; + file = td->td_fpop; ldev = dev->si_drv1; if (ldev == NULL) return (0); @@ -525,6 +557,7 @@ linux_dev_write(struct cdev *dev, struct uio *uio, int ioflag) /* XXX no support for I/O vectors currently */ if (uio->uio_iovcnt != 1) return (EOPNOTSUPP); + linux_set_current(td, &t); if (filp->f_op->write) { bytes = filp->f_op->write(filp, uio->uio_iov->iov_base, uio->uio_iov->iov_len, &uio->uio_offset); @@ -537,6 +570,7 @@ linux_dev_write(struct cdev *dev, struct uio *uio, int ioflag) error = -bytes; } else error = ENXIO; + linux_clear_current(td); return (error); } @@ -546,21 +580,24 @@ linux_dev_poll(struct cdev *dev, int events, struct thread *td) { struct linux_cdev *ldev; struct linux_file *filp; + struct task_struct t; struct file *file; int revents; int error; - file = curthread->td_fpop; + file = td->td_fpop; ldev = dev->si_drv1; if (ldev == NULL) return (0); if ((error = devfs_get_cdevpriv((void **)&filp)) != 0) return (error); filp->f_flags = file->f_flag; + linux_set_current(td, &t); if (filp->f_op->poll) revents = filp->f_op->poll(filp, NULL) & events; else revents = 0; + linux_clear_current(td); return (revents); } @@ -571,17 +608,21 @@ linux_dev_mmap_single(struct cdev *dev, vm_ooffset_t *offset, { struct linux_cdev *ldev; struct linux_file *filp; + struct thread *td; + struct task_struct t; struct file *file; struct vm_area_struct vma; int error; - file = curthread->td_fpop; + td = curthread; + file = td->td_fpop; ldev = dev->si_drv1; if (ldev == NULL) return (ENODEV); if ((error = devfs_get_cdevpriv((void **)&filp)) != 0) return (error); filp->f_flags = file->f_flag; + linux_set_current(td, &t); vma.vm_start = 0; vma.vm_end = size; vma.vm_pgoff = *offset / PAGE_SIZE; @@ -596,10 +637,11 @@ linux_dev_mmap_single(struct cdev *dev, vm_ooffset_t *offset, sglist_append_phys(sg, (vm_paddr_t)vma.vm_pfn << PAGE_SHIFT, vma.vm_len); *object = vm_pager_allocate(OBJT_SG, sg, vma.vm_len, - nprot, 0, curthread->td_ucred); + nprot, 0, td->td_ucred); if (*object == NULL) { sglist_free(sg); - return (EINVAL); + error = EINVAL; + goto done; } *offset = 0; if (vma.vm_page_prot != VM_MEMATTR_DEFAULT) { @@ -611,7 +653,8 @@ linux_dev_mmap_single(struct cdev *dev, vm_ooffset_t *offset, } } else error = ENODEV; - +done: + linux_clear_current(td); return (error); } @@ -632,6 +675,7 @@ linux_file_read(struct file *file, struct uio *uio, struct ucred *active_cred, int flags, struct thread *td) { struct linux_file *filp; + struct task_struct t; ssize_t bytes; int error; @@ -641,6 +685,7 @@ linux_file_read(struct file *file, struct uio *uio, struct ucred *active_cred, /* XXX no support for I/O vectors currently */ if (uio->uio_iovcnt != 1) return (EOPNOTSUPP); + linux_set_current(td, &t); if (filp->f_op->read) { bytes = filp->f_op->read(filp, uio->uio_iov->iov_base, uio->uio_iov->iov_len, &uio->uio_offset); @@ -653,6 +698,7 @@ linux_file_read(struct file *file, struct uio *uio, struct ucred *active_cred, error = -bytes; } else error = ENXIO; + linux_clear_current(td); return (error); } @@ -662,14 +708,17 @@ linux_file_poll(struct file *file, int events, struct ucred *active_cred, struct thread *td) { struct linux_file *filp; + struct task_struct t; int revents; filp = (struct linux_file *)file->f_data; filp->f_flags = file->f_flag; + linux_set_current(td, &t); if (filp->f_op->poll) revents = filp->f_op->poll(filp, NULL) & events; else revents = 0; + linux_clear_current(td); return (revents); } @@ -678,11 +727,14 @@ static int linux_file_close(struct file *file, struct thread *td) { struct linux_file *filp; + struct task_struct t; int error; filp = (struct linux_file *)file->f_data; filp->f_flags = file->f_flag; + linux_set_current(td, &t); error = -filp->f_op->release(NULL, filp); + linux_clear_current(td); funsetown(&filp->f_sigio); kfree(filp); @@ -694,12 +746,14 @@ linux_file_ioctl(struct file *fp, u_long cmd, void *data, struct ucred *cred, struct thread *td) { struct linux_file *filp; + struct task_struct t; int error; filp = (struct linux_file *)fp->f_data; filp->f_flags = fp->f_flag; error = 0; + linux_set_current(td, &t); switch (cmd) { case FIONBIO: break; @@ -721,6 +775,7 @@ linux_file_ioctl(struct file *fp, u_long cmd, void *data, struct ucred *cred, error = ENOTTY; break; } + linux_clear_current(td); return (error); } |