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
This commit is contained in:
Hans Petter Selasky 2017-02-21 12:43:02 +00:00
parent 27569d019d
commit 1e3db1de0c
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=314040
22 changed files with 312 additions and 178 deletions

View File

@ -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>

View File

@ -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_ */

View File

@ -39,6 +39,7 @@
#include <sys/proc.h>
#include <linux/fs.h>
#include <linux/slab.h>
struct linux_file;

View File

@ -32,7 +32,6 @@
#define _LINUX_JIFFIES_H_
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/time.h>
#include <sys/time.h>

View File

@ -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))

View File

@ -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>

View File

@ -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;
#include <sys/unistd.h>
#include <sys/kthread.h>
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);
}
#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_ */

View File

@ -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;

View File

@ -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;

View File

@ -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))

View File

@ -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

View File

@ -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 {

View File

@ -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_ */

View File

@ -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>

View File

@ -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);
}

View File

@ -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);

View File

@ -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();
}

View File

@ -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);

View File

@ -4266,6 +4266,10 @@ compat/linuxkpi/common/src/linux_kmod.c optional compat_linuxkpi \
compile-with "${LINUXKPI_C}"
compat/linuxkpi/common/src/linux_compat.c optional compat_linuxkpi \
compile-with "${LINUXKPI_C}"
compat/linuxkpi/common/src/linux_current.c optional compat_linuxkpi \
compile-with "${LINUXKPI_C}"
compat/linuxkpi/common/src/linux_kthread.c optional compat_linuxkpi \
compile-with "${LINUXKPI_C}"
compat/linuxkpi/common/src/linux_pci.c optional compat_linuxkpi pci \
compile-with "${LINUXKPI_C}"
compat/linuxkpi/common/src/linux_idr.c optional compat_linuxkpi \

View File

@ -4,6 +4,8 @@
KMOD= linuxkpi
SRCS= linux_kmod.c \
linux_compat.c \
linux_current.c \
linux_kthread.c \
linux_pci.c \
linux_radix.c \
linux_idr.c \

View File

@ -58,7 +58,7 @@
* in the range 5 to 9.
*/
#undef __FreeBSD_version
#define __FreeBSD_version 1200021 /* Master, propagated to newvers */
#define __FreeBSD_version 1200022 /* Master, propagated to newvers */
/*
* __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,

View File

@ -339,6 +339,7 @@ struct thread {
void *td_emuldata; /* Emulator state data */
int td_lastcpu; /* (t) Last cpu we were on. */
int td_oncpu; /* (t) Which cpu we are on. */
void *td_lkpi_task; /* LinuxKPI task struct pointer */
};
struct thread0_storage {