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:
parent
823c0e8c36
commit
5a4680a865
@ -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>
|
||||
|
@ -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_ */
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include <sys/proc.h>
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
struct linux_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>
|
||||
|
@ -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))
|
||||
|
@ -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>
|
||||
|
@ -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_ */
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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 *)¤t->state, (x))
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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_ */
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
94
sys/compat/linuxkpi/common/src/linux_current.c
Normal file
94
sys/compat/linuxkpi/common/src/linux_current.c
Normal 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);
|
120
sys/compat/linuxkpi/common/src/linux_kthread.c
Normal file
120
sys/compat/linuxkpi/common/src/linux_kthread.c
Normal 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(¤t->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();
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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 \
|
||||
|
@ -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 \
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user