aboutsummaryrefslogtreecommitdiff
path: root/sys/compat/linuxkpi
diff options
context:
space:
mode:
authorHans Petter Selasky <hselasky@FreeBSD.org>2017-02-21 12:43:02 +0000
committerHans Petter Selasky <hselasky@FreeBSD.org>2017-02-21 12:43:02 +0000
commit1e3db1de0cf6b904373e0f4c9e738b9713f3e17b (patch)
tree9c3eb36eac0b6065dcb12dfdf875957ee7c51293 /sys/compat/linuxkpi
parent27569d019d4edb44094fab5f2fa60ad2b8b03bb7 (diff)
downloadsrc-1e3db1de0cf6b904373e0f4c9e738b9713f3e17b.tar.gz
src-1e3db1de0cf6b904373e0f4c9e738b9713f3e17b.zip
Make the LinuxKPI task struct persistent accross system calls.
A set of helper functions have been added to manage the life of the LinuxKPI task struct. When an external system call or task is invoked, a check is made to create the task struct by demand. A thread destructor callback is registered to free the task struct when a thread exits to avoid memory leaks. This change lays the ground for emulating the Linux kernel more closely which is a dependency by the code using the LinuxKPI APIs. Add new dedicated td_lkpi_task field has been added to struct thread instead of abusing td_retval[1]. Fix some header file inclusions to make LINT kernel build properly after this change. Bump the __FreeBSD_version to force a rebuild of all kernel modules. MFC after: 1 week Sponsored by: Mellanox Technologies
Notes
Notes: svn path=/head/; revision=314040
Diffstat (limited to 'sys/compat/linuxkpi')
-rw-r--r--sys/compat/linuxkpi/common/include/linux/bitops.h1
-rw-r--r--sys/compat/linuxkpi/common/include/linux/compat.h25
-rw-r--r--sys/compat/linuxkpi/common/include/linux/file.h1
-rw-r--r--sys/compat/linuxkpi/common/include/linux/jiffies.h1
-rw-r--r--sys/compat/linuxkpi/common/include/linux/kdev_t.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/kernel.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/kthread.h81
-rw-r--r--sys/compat/linuxkpi/common/include/linux/rwlock.h1
-rw-r--r--sys/compat/linuxkpi/common/include/linux/rwsem.h1
-rw-r--r--sys/compat/linuxkpi/common/include/linux/sched.h45
-rw-r--r--sys/compat/linuxkpi/common/include/linux/semaphore.h1
-rw-r--r--sys/compat/linuxkpi/common/include/linux/spinlock.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/types.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/wait.h2
-rw-r--r--sys/compat/linuxkpi/common/src/linux_compat.c69
-rw-r--r--sys/compat/linuxkpi/common/src/linux_current.c94
-rw-r--r--sys/compat/linuxkpi/common/src/linux_kthread.c120
-rw-r--r--sys/compat/linuxkpi/common/src/linux_pci.c31
18 files changed, 304 insertions, 177 deletions
diff --git a/sys/compat/linuxkpi/common/include/linux/bitops.h b/sys/compat/linuxkpi/common/include/linux/bitops.h
index 9e1fa2bc4569..2c521318804f 100644
--- a/sys/compat/linuxkpi/common/include/linux/bitops.h
+++ b/sys/compat/linuxkpi/common/include/linux/bitops.h
@@ -31,6 +31,7 @@
#ifndef _LINUX_BITOPS_H_
#define _LINUX_BITOPS_H_
+#include <sys/param.h>
#include <sys/types.h>
#include <sys/systm.h>
#include <sys/errno.h>
diff --git a/sys/compat/linuxkpi/common/include/linux/compat.h b/sys/compat/linuxkpi/common/include/linux/compat.h
index 01b8a85b9760..62ea3363394b 100644
--- a/sys/compat/linuxkpi/common/include/linux/compat.h
+++ b/sys/compat/linuxkpi/common/include/linux/compat.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-2017 Mellanox Technologies, Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -31,10 +31,29 @@
#ifndef _LINUX_COMPAT_H_
#define _LINUX_COMPAT_H_
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/malloc.h>
+
struct thread;
struct task_struct;
-void linux_set_current(struct thread *td, struct task_struct *t);
-void linux_clear_current(struct thread *td);
+extern int linux_alloc_current(struct thread *, int flags);
+extern void linux_free_current(struct task_struct *);
+
+static inline void
+linux_set_current(struct thread *td)
+{
+ if (__predict_false(td->td_lkpi_task == NULL))
+ linux_alloc_current(td, M_WAITOK);
+}
+
+static inline int
+linux_set_current_flags(struct thread *td, int flags)
+{
+ if (__predict_false(td->td_lkpi_task == NULL))
+ return (linux_alloc_current(td, flags));
+ return (0);
+}
#endif /* _LINUX_COMPAT_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/file.h b/sys/compat/linuxkpi/common/include/linux/file.h
index 559ac0437681..0661e70a5697 100644
--- a/sys/compat/linuxkpi/common/include/linux/file.h
+++ b/sys/compat/linuxkpi/common/include/linux/file.h
@@ -39,6 +39,7 @@
#include <sys/proc.h>
#include <linux/fs.h>
+#include <linux/slab.h>
struct linux_file;
diff --git a/sys/compat/linuxkpi/common/include/linux/jiffies.h b/sys/compat/linuxkpi/common/include/linux/jiffies.h
index 9a85f616152a..a95e6064f41c 100644
--- a/sys/compat/linuxkpi/common/include/linux/jiffies.h
+++ b/sys/compat/linuxkpi/common/include/linux/jiffies.h
@@ -32,7 +32,6 @@
#define _LINUX_JIFFIES_H_
#include <linux/types.h>
-#include <linux/kernel.h>
#include <linux/time.h>
#include <sys/time.h>
diff --git a/sys/compat/linuxkpi/common/include/linux/kdev_t.h b/sys/compat/linuxkpi/common/include/linux/kdev_t.h
index c0bb97e5ba42..447d7af2f842 100644
--- a/sys/compat/linuxkpi/common/include/linux/kdev_t.h
+++ b/sys/compat/linuxkpi/common/include/linux/kdev_t.h
@@ -31,6 +31,8 @@
#ifndef _LINUX_KDEV_T_H_
#define _LINUX_KDEV_T_H_
+#include <sys/types.h>
+
#define MAJOR(dev) major((dev))
#define MINOR(dev) minor((dev))
#define MKDEV(ma, mi) makedev((ma), (mi))
diff --git a/sys/compat/linuxkpi/common/include/linux/kernel.h b/sys/compat/linuxkpi/common/include/linux/kernel.h
index ead6a8a72bfe..fabdba5df517 100644
--- a/sys/compat/linuxkpi/common/include/linux/kernel.h
+++ b/sys/compat/linuxkpi/common/include/linux/kernel.h
@@ -45,7 +45,7 @@
#include <linux/bitops.h>
#include <linux/compiler.h>
#include <linux/errno.h>
-#include <linux/kthread.h>
+#include <linux/sched.h>
#include <linux/types.h>
#include <linux/jiffies.h>
#include <linux/wait.h>
diff --git a/sys/compat/linuxkpi/common/include/linux/kthread.h b/sys/compat/linuxkpi/common/include/linux/kthread.h
index 2e0da123d528..eaf2b31a71ab 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-2016 Mellanox Technologies, Ltd.
+ * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -31,74 +31,27 @@
#ifndef _LINUX_KTHREAD_H_
#define _LINUX_KTHREAD_H_
-#include <sys/param.h>
-#include <sys/lock.h>
-#include <sys/mutex.h>
-#include <sys/kernel.h>
-#include <sys/kthread.h>
-#include <sys/sleepqueue.h>
-
-#include <linux/slab.h>
#include <linux/sched.h>
-static inline void
-linux_kthread_fn(void *arg)
-{
- struct task_struct *task;
- struct thread *td = curthread;
-
- task = arg;
- 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(td->td_proc);
- task->should_stop = TASK_STOPPED;
- wakeup(task);
- PROC_UNLOCK(td->td_proc);
- task_struct_set(td, NULL);
- kthread_exit();
-}
-
-static inline struct task_struct *
-linux_kthread_create(int (*threadfn)(void *data), void *data)
-{
- struct task_struct *task;
-
- task = kzalloc(sizeof(*task), GFP_KERNEL);
- task->task_fn = threadfn;
- task->task_data = data;
-
- return (task);
-}
+#include <sys/unistd.h>
+#include <sys/kthread.h>
-#define kthread_run(fn, data, fmt, ...) \
-({ \
- struct task_struct *_task; \
+#define kthread_run(fn, data, fmt, ...) ({ \
+ struct task_struct *__task; \
+ struct thread *__td; \
\
- _task = linux_kthread_create((fn), (data)); \
- if (kthread_add(linux_kthread_fn, _task, NULL, &_task->task_thread, \
- 0, 0, fmt, ## __VA_ARGS__)) { \
- kfree(_task); \
- _task = NULL; \
- } \
- _task; \
+ if (kthread_add(linux_kthread_fn, NULL, NULL, &__td, \
+ RFSTOPPED, 0, fmt, ## __VA_ARGS__)) \
+ __task = NULL; \
+ else \
+ __task = linux_kthread_setup_and_run(__td, fn, data); \
+ __task; \
})
-#define kthread_should_stop() current->should_stop
-
-static inline int
-kthread_stop(struct task_struct *task)
-{
-
- PROC_LOCK(task->task_thread->td_proc);
- task->should_stop = TASK_SHOULD_STOP;
- wake_up_process(task);
- while (task->should_stop != TASK_STOPPED)
- msleep(task, &task->task_thread->td_proc->p_mtx, PWAIT,
- "kstop", hz);
- PROC_UNLOCK(task->task_thread->td_proc);
- return task->task_ret;
-}
+extern int kthread_stop(struct task_struct *);
+extern bool kthread_should_stop_task(struct task_struct *);
+extern bool kthread_should_stop(void);
+extern void linux_kthread_fn(void *);
+extern struct task_struct *linux_kthread_setup_and_run(struct thread *, linux_task_fn_t *, void *arg);
#endif /* _LINUX_KTHREAD_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/rwlock.h b/sys/compat/linuxkpi/common/include/linux/rwlock.h
index 54c53dc94988..4c9529e843ef 100644
--- a/sys/compat/linuxkpi/common/include/linux/rwlock.h
+++ b/sys/compat/linuxkpi/common/include/linux/rwlock.h
@@ -34,6 +34,7 @@
#include <sys/types.h>
#include <sys/lock.h>
#include <sys/rwlock.h>
+#include <sys/libkern.h>
typedef struct {
struct rwlock rw;
diff --git a/sys/compat/linuxkpi/common/include/linux/rwsem.h b/sys/compat/linuxkpi/common/include/linux/rwsem.h
index 22ad4dc62a94..7ca066125a48 100644
--- a/sys/compat/linuxkpi/common/include/linux/rwsem.h
+++ b/sys/compat/linuxkpi/common/include/linux/rwsem.h
@@ -34,6 +34,7 @@
#include <sys/param.h>
#include <sys/lock.h>
#include <sys/sx.h>
+#include <sys/libkern.h>
struct rw_semaphore {
struct sx sx;
diff --git a/sys/compat/linuxkpi/common/include/linux/sched.h b/sys/compat/linuxkpi/common/include/linux/sched.h
index c9f2a399904e..04abc8230775 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-2016 Mellanox Technologies, Ltd.
+ * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -37,6 +37,12 @@
#include <sys/sched.h>
#include <sys/sleepqueue.h>
+#include <linux/types.h>
+#include <linux/completion.h>
+#include <linux/slab.h>
+
+#include <asm/atomic.h>
+
#define MAX_SCHEDULE_TIMEOUT LONG_MAX
#define TASK_RUNNING 0
@@ -46,41 +52,22 @@
#define TASK_WAKEKILL 128
#define TASK_WAKING 256
-#define TASK_SHOULD_STOP 1
-#define TASK_STOPPED 2
-
-/*
- * 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;
- int (*task_fn)(void *data);
- void *task_data;
+ struct thread *task_thread;
+ linux_task_fn_t *task_fn;
+ void *task_data;
int task_ret;
int state;
- int should_stop;
+ atomic_t kthread_flags;
pid_t pid;
const char *comm;
- void *bsd_ioctl_data;
- unsigned bsd_ioctl_len;
+ void *bsd_ioctl_data;
+ unsigned bsd_ioctl_len;
+ struct completion parked;
+ struct completion exited;
};
-#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 */
-CTASSERT(sizeof(((struct thread *)0)->td_retval[1]) >= sizeof(uintptr_t));
+#define current ((struct task_struct *)curthread->td_lkpi_task)
#define set_current_state(x) \
atomic_store_rel_int((volatile int *)&current->state, (x))
diff --git a/sys/compat/linuxkpi/common/include/linux/semaphore.h b/sys/compat/linuxkpi/common/include/linux/semaphore.h
index 022a0164840f..59a35311a5cc 100644
--- a/sys/compat/linuxkpi/common/include/linux/semaphore.h
+++ b/sys/compat/linuxkpi/common/include/linux/semaphore.h
@@ -34,6 +34,7 @@
#include <sys/param.h>
#include <sys/lock.h>
#include <sys/sema.h>
+#include <sys/libkern.h>
/*
* XXX BSD semaphores are disused and slow. They also do not provide a
diff --git a/sys/compat/linuxkpi/common/include/linux/spinlock.h b/sys/compat/linuxkpi/common/include/linux/spinlock.h
index 97c83e0ed034..4beb6fe45f2d 100644
--- a/sys/compat/linuxkpi/common/include/linux/spinlock.h
+++ b/sys/compat/linuxkpi/common/include/linux/spinlock.h
@@ -35,9 +35,9 @@
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/mutex.h>
+#include <sys/libkern.h>
#include <linux/compiler.h>
-#include <linux/kernel.h>
#include <linux/rwlock.h>
typedef struct {
diff --git a/sys/compat/linuxkpi/common/include/linux/types.h b/sys/compat/linuxkpi/common/include/linux/types.h
index c9c37284a706..28abc9ec269d 100644
--- a/sys/compat/linuxkpi/common/include/linux/types.h
+++ b/sys/compat/linuxkpi/common/include/linux/types.h
@@ -63,4 +63,6 @@ typedef u64 phys_addr_t;
#define DECLARE_BITMAP(n, bits) \
unsigned long n[howmany(bits, sizeof(long) * 8)]
+typedef int linux_task_fn_t(void *data);
+
#endif /* _LINUX_TYPES_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/wait.h b/sys/compat/linuxkpi/common/include/linux/wait.h
index 7ae6464c6d4e..14da6d264cec 100644
--- a/sys/compat/linuxkpi/common/include/linux/wait.h
+++ b/sys/compat/linuxkpi/common/include/linux/wait.h
@@ -32,8 +32,6 @@
#define _LINUX_WAIT_H_
#include <linux/compiler.h>
-#include <linux/spinlock.h>
-#include <linux/sched.h>
#include <linux/list.h>
#include <linux/jiffies.h>
diff --git a/sys/compat/linuxkpi/common/src/linux_compat.c b/sys/compat/linuxkpi/common/src/linux_compat.c
index 54bd33bc7ad7..2b94a03e7e9f 100644
--- a/sys/compat/linuxkpi/common/src/linux_compat.c
+++ b/sys/compat/linuxkpi/common/src/linux_compat.c
@@ -384,32 +384,14 @@ kobject_init_and_add(struct kobject *kobj, const struct kobj_type *ktype,
return kobject_add_complete(kobj, parent);
}
-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);
-}
-
-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;
+ linux_set_current(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);
}
@@ -419,7 +401,6 @@ 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;
@@ -433,7 +414,7 @@ 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);
+ linux_set_current(td);
if (filp->f_op->open) {
error = -filp->f_op->open(file->f_vnode, filp);
if (error) {
@@ -447,7 +428,6 @@ linux_dev_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
kfree(filp);
}
done:
- linux_clear_current(td);
return (error);
}
@@ -538,7 +518,6 @@ 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;
unsigned size;
int error;
@@ -550,7 +529,8 @@ linux_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
if ((error = devfs_get_cdevpriv((void **)&filp)) != 0)
return (error);
filp->f_flags = file->f_flag;
- linux_set_current(td, &t);
+
+ linux_set_current(td);
size = IOCPARM_LEN(cmd);
/* refer to logic in sys_ioctl() */
if (size > 0) {
@@ -560,8 +540,8 @@ linux_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
* Background: Linux code expects a user-space address
* while FreeBSD supplies a kernel-space address.
*/
- t.bsd_ioctl_data = data;
- t.bsd_ioctl_len = size;
+ current->bsd_ioctl_data = data;
+ current->bsd_ioctl_len = size;
data = (void *)LINUX_IOCTL_MIN_PTR;
} else {
/* fetch user-space pointer */
@@ -571,7 +551,10 @@ 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);
+ if (size > 0) {
+ current->bsd_ioctl_data = NULL;
+ current->bsd_ioctl_len = 0;
+ }
return (error);
}
@@ -581,7 +564,6 @@ 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;
@@ -598,7 +580,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);
+ linux_set_current(td);
if (filp->f_op->read) {
bytes = filp->f_op->read(filp, uio->uio_iov->iov_base,
uio->uio_iov->iov_len, &uio->uio_offset);
@@ -611,7 +593,6 @@ linux_dev_read(struct cdev *dev, struct uio *uio, int ioflag)
error = -bytes;
} else
error = ENXIO;
- linux_clear_current(td);
return (error);
}
@@ -621,7 +602,6 @@ 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;
@@ -638,7 +618,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);
+ linux_set_current(td);
if (filp->f_op->write) {
bytes = filp->f_op->write(filp, uio->uio_iov->iov_base,
uio->uio_iov->iov_len, &uio->uio_offset);
@@ -651,7 +631,6 @@ linux_dev_write(struct cdev *dev, struct uio *uio, int ioflag)
error = -bytes;
} else
error = ENXIO;
- linux_clear_current(td);
return (error);
}
@@ -661,7 +640,6 @@ 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;
@@ -673,12 +651,11 @@ linux_dev_poll(struct cdev *dev, int events, struct thread *td)
if ((error = devfs_get_cdevpriv((void **)&filp)) != 0)
return (error);
filp->f_flags = file->f_flag;
- linux_set_current(td, &t);
+ linux_set_current(td);
if (filp->f_op->poll)
revents = filp->f_op->poll(filp, NULL) & events;
else
revents = 0;
- linux_clear_current(td);
return (revents);
}
@@ -690,7 +667,6 @@ 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;
@@ -703,7 +679,7 @@ linux_dev_mmap_single(struct cdev *dev, vm_ooffset_t *offset,
if ((error = devfs_get_cdevpriv((void **)&filp)) != 0)
return (error);
filp->f_flags = file->f_flag;
- linux_set_current(td, &t);
+ linux_set_current(td);
vma.vm_start = 0;
vma.vm_end = size;
vma.vm_pgoff = *offset / PAGE_SIZE;
@@ -735,7 +711,6 @@ linux_dev_mmap_single(struct cdev *dev, vm_ooffset_t *offset,
} else
error = ENODEV;
done:
- linux_clear_current(td);
return (error);
}
@@ -756,7 +731,6 @@ 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;
@@ -766,7 +740,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);
+ linux_set_current(td);
if (filp->f_op->read) {
bytes = filp->f_op->read(filp, uio->uio_iov->iov_base,
uio->uio_iov->iov_len, &uio->uio_offset);
@@ -779,7 +753,6 @@ linux_file_read(struct file *file, struct uio *uio, struct ucred *active_cred,
error = -bytes;
} else
error = ENXIO;
- linux_clear_current(td);
return (error);
}
@@ -789,17 +762,15 @@ 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);
+ linux_set_current(td);
if (filp->f_op->poll)
revents = filp->f_op->poll(filp, NULL) & events;
else
revents = 0;
- linux_clear_current(td);
return (revents);
}
@@ -808,14 +779,12 @@ 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);
+ linux_set_current(td);
error = -filp->f_op->release(NULL, filp);
- linux_clear_current(td);
funsetown(&filp->f_sigio);
kfree(filp);
@@ -827,14 +796,13 @@ 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);
+ linux_set_current(td);
switch (cmd) {
case FIONBIO:
break;
@@ -856,7 +824,6 @@ linux_file_ioctl(struct file *fp, u_long cmd, void *data, struct ucred *cred,
error = ENOTTY;
break;
}
- linux_clear_current(td);
return (error);
}
diff --git a/sys/compat/linuxkpi/common/src/linux_current.c b/sys/compat/linuxkpi/common/src/linux_current.c
new file mode 100644
index 000000000000..6b4442cb4bce
--- /dev/null
+++ b/sys/compat/linuxkpi/common/src/linux_current.c
@@ -0,0 +1,94 @@
+/*-
+ * Copyright (c) 2017 Hans Petter Selasky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <linux/compat.h>
+#include <linux/mm.h>
+#include <linux/kthread.h>
+
+#include <sys/kernel.h>
+#include <sys/eventhandler.h>
+#include <sys/malloc.h>
+
+static eventhandler_tag linuxkpi_thread_dtor_tag;
+
+static MALLOC_DEFINE(M_LINUX_CURRENT, "linuxcurrent", "LinuxKPI task structure");
+
+int
+linux_alloc_current(struct thread *td, int flags)
+{
+ struct task_struct *ts;
+
+ MPASS(td->td_lkpi_task == NULL);
+
+ ts = malloc(sizeof(*ts), M_LINUX_CURRENT, flags | M_ZERO);
+ if (ts == NULL)
+ return (ENOMEM);
+
+ atomic_set(&ts->kthread_flags, 0);
+ ts->task_thread = td;
+ ts->comm = td->td_name;
+ ts->pid = td->td_tid;
+ ts->state = TASK_RUNNING;
+ td->td_lkpi_task = ts;
+ return (0);
+}
+
+void
+linux_free_current(struct task_struct *ts)
+{
+ free(ts, M_LINUX_CURRENT);
+}
+
+static void
+linuxkpi_thread_dtor(void *arg __unused, struct thread *td)
+{
+ struct task_struct *ts;
+
+ ts = td->td_lkpi_task;
+ if (ts == NULL)
+ return;
+
+ td->td_lkpi_task = NULL;
+ free(ts, M_LINUX_CURRENT);
+}
+
+static void
+linux_current_init(void *arg __unused)
+{
+ linuxkpi_thread_dtor_tag = EVENTHANDLER_REGISTER(thread_dtor,
+ linuxkpi_thread_dtor, NULL, EVENTHANDLER_PRI_ANY);
+}
+SYSINIT(linux_current, SI_SUB_EVENTHANDLER, SI_ORDER_SECOND, linux_current_init, NULL);
+
+static void
+linux_current_uninit(void *arg __unused)
+{
+ EVENTHANDLER_DEREGISTER(thread_dtor, linuxkpi_thread_dtor_tag);
+}
+SYSUNINIT(linux_current, SI_SUB_EVENTHANDLER, SI_ORDER_SECOND, linux_current_uninit, NULL);
diff --git a/sys/compat/linuxkpi/common/src/linux_kthread.c b/sys/compat/linuxkpi/common/src/linux_kthread.c
new file mode 100644
index 000000000000..90da31f1ad0a
--- /dev/null
+++ b/sys/compat/linuxkpi/common/src/linux_kthread.c
@@ -0,0 +1,120 @@
+/*-
+ * Copyright (c) 2017 Hans Petter Selasky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <linux/kthread.h>
+#include <linux/sched.h>
+#include <linux/compat.h>
+
+#include <sys/bus.h>
+#include <sys/interrupt.h>
+#include <sys/priority.h>
+
+enum {
+ KTHREAD_SHOULD_STOP_MASK = (1 << 0),
+ KTHREAD_SHOULD_PARK_MASK = (1 << 1),
+ KTHREAD_IS_PARKED_MASK = (1 << 2),
+};
+
+bool
+kthread_should_stop_task(struct task_struct *task)
+{
+
+ return (atomic_read(&task->kthread_flags) & KTHREAD_SHOULD_STOP_MASK);
+}
+
+bool
+kthread_should_stop(void)
+{
+
+ return (atomic_read(&current->kthread_flags) & KTHREAD_SHOULD_STOP_MASK);
+}
+
+int
+kthread_stop(struct task_struct *task)
+{
+ int retval;
+
+ /*
+ * Assume task is still alive else caller should not call
+ * kthread_stop():
+ */
+ atomic_or(KTHREAD_SHOULD_STOP_MASK, &task->kthread_flags);
+ wake_up_process(task);
+ wait_for_completion(&task->exited);
+
+ /*
+ * Get return code and free task structure:
+ */
+ retval = task->task_ret;
+ linux_free_current(task);
+
+ return (retval);
+}
+
+struct task_struct *
+linux_kthread_setup_and_run(struct thread *td, linux_task_fn_t *task_fn, void *arg)
+{
+ struct task_struct *task;
+
+ linux_set_current(td);
+
+ task = td->td_lkpi_task;
+ task->task_fn = task_fn;
+ task->task_data = arg;
+
+ thread_lock(td);
+ /* make sure the scheduler priority is raised */
+ sched_prio(td, PI_SWI(SWI_NET));
+ /* put thread into run-queue */
+ sched_add(td, SRQ_BORING);
+ thread_unlock(td);
+
+ return (task);
+}
+
+void
+linux_kthread_fn(void *arg __unused)
+{
+ struct task_struct *task = current;
+
+ if (kthread_should_stop_task(task) == 0)
+ task->task_ret = task->task_fn(task->task_data);
+
+ if (kthread_should_stop_task(task) != 0) {
+ struct thread *td = curthread;
+
+ /* let kthread_stop() free data */
+ td->td_lkpi_task = NULL;
+
+ /* wakeup kthread_stop() */
+ complete(&task->exited);
+ }
+ kthread_exit();
+}
+
diff --git a/sys/compat/linuxkpi/common/src/linux_pci.c b/sys/compat/linuxkpi/common/src/linux_pci.c
index 22db26495e58..84a38d875564 100644
--- a/sys/compat/linuxkpi/common/src/linux_pci.c
+++ b/sys/compat/linuxkpi/common/src/linux_pci.c
@@ -121,12 +121,9 @@ linux_pci_attach(device_t dev)
struct pci_dev *pdev;
struct pci_driver *pdrv;
const struct pci_device_id *id;
- struct task_struct t;
- struct thread *td;
int error;
- td = curthread;
- linux_set_current(td, &t);
+ linux_set_current(curthread);
pdrv = linux_pci_find(dev, &id);
pdev = device_get_softc(dev);
pdev->dev.parent = &linux_root_device;
@@ -159,7 +156,6 @@ linux_pci_attach(device_t dev)
put_device(&pdev->dev);
error = -error;
}
- linux_clear_current(td);
return (error);
}
@@ -167,11 +163,8 @@ static int
linux_pci_detach(device_t dev)
{
struct pci_dev *pdev;
- struct task_struct t;
- struct thread *td;
- td = curthread;
- linux_set_current(td, &t);
+ linux_set_current(curthread);
pdev = device_get_softc(dev);
DROP_GIANT();
pdev->pdrv->remove(pdev);
@@ -180,7 +173,6 @@ linux_pci_detach(device_t dev)
list_del(&pdev->links);
spin_unlock(&pci_lock);
put_device(&pdev->dev);
- linux_clear_current(td);
return (0);
}
@@ -190,18 +182,14 @@ linux_pci_suspend(device_t dev)
{
struct pm_message pm = { };
struct pci_dev *pdev;
- struct task_struct t;
- struct thread *td;
int err;
- td = curthread;
- linux_set_current(td, &t);
+ linux_set_current(curthread);
pdev = device_get_softc(dev);
if (pdev->pdrv->suspend != NULL)
err = -pdev->pdrv->suspend(pdev, pm);
else
err = 0;
- linux_clear_current(td);
return (err);
}
@@ -209,18 +197,14 @@ static int
linux_pci_resume(device_t dev)
{
struct pci_dev *pdev;
- struct task_struct t;
- struct thread *td;
int err;
- td = curthread;
- linux_set_current(td, &t);
+ linux_set_current(curthread);
pdev = device_get_softc(dev);
if (pdev->pdrv->resume != NULL)
err = -pdev->pdrv->resume(pdev);
else
err = 0;
- linux_clear_current(td);
return (err);
}
@@ -228,18 +212,14 @@ static int
linux_pci_shutdown(device_t dev)
{
struct pci_dev *pdev;
- struct task_struct t;
- struct thread *td;
- td = curthread;
- linux_set_current(td, &t);
+ linux_set_current(curthread);
pdev = device_get_softc(dev);
if (pdev->pdrv->shutdown != NULL) {
DROP_GIANT();
pdev->pdrv->shutdown(pdev);
PICKUP_GIANT();
}
- linux_clear_current(td);
return (0);
}
@@ -251,6 +231,7 @@ pci_register_driver(struct pci_driver *pdrv)
bus = devclass_find("pci");
+ linux_set_current(curthread);
spin_lock(&pci_lock);
list_add(&pdrv->links, &pci_drivers);
spin_unlock(&pci_lock);