aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/compat/linuxkpi/common/include/linux/kthread.h11
-rw-r--r--sys/compat/linuxkpi/common/include/linux/sched.h19
-rw-r--r--sys/compat/linuxkpi/common/src/linux_compat.c83
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);
}