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:
hselasky 2017-02-21 12:43:02 +00:00
parent 823c0e8c36
commit 5a4680a865
22 changed files with 312 additions and 178 deletions

View File

@ -31,6 +31,7 @@
#ifndef _LINUX_BITOPS_H_ #ifndef _LINUX_BITOPS_H_
#define _LINUX_BITOPS_H_ #define _LINUX_BITOPS_H_
#include <sys/param.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/systm.h> #include <sys/systm.h>
#include <sys/errno.h> #include <sys/errno.h>

View File

@ -2,7 +2,7 @@
* Copyright (c) 2010 Isilon Systems, Inc. * Copyright (c) 2010 Isilon Systems, Inc.
* Copyright (c) 2010 iX Systems, Inc. * Copyright (c) 2010 iX Systems, Inc.
* Copyright (c) 2010 Panasas, Inc. * Copyright (c) 2010 Panasas, Inc.
* Copyright (c) 2013, 2014 Mellanox Technologies, Ltd. * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -31,10 +31,29 @@
#ifndef _LINUX_COMPAT_H_ #ifndef _LINUX_COMPAT_H_
#define _LINUX_COMPAT_H_ #define _LINUX_COMPAT_H_
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/malloc.h>
struct thread; struct thread;
struct task_struct; struct task_struct;
void linux_set_current(struct thread *td, struct task_struct *t); extern int linux_alloc_current(struct thread *, int flags);
void linux_clear_current(struct thread *td); 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_ */ #endif /* _LINUX_COMPAT_H_ */

View File

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

View File

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

View File

@ -31,6 +31,8 @@
#ifndef _LINUX_KDEV_T_H_ #ifndef _LINUX_KDEV_T_H_
#define _LINUX_KDEV_T_H_ #define _LINUX_KDEV_T_H_
#include <sys/types.h>
#define MAJOR(dev) major((dev)) #define MAJOR(dev) major((dev))
#define MINOR(dev) minor((dev)) #define MINOR(dev) minor((dev))
#define MKDEV(ma, mi) makedev((ma), (mi)) #define MKDEV(ma, mi) makedev((ma), (mi))

View File

@ -45,7 +45,7 @@
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/kthread.h> #include <linux/sched.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/wait.h> #include <linux/wait.h>

View File

@ -2,7 +2,7 @@
* Copyright (c) 2010 Isilon Systems, Inc. * Copyright (c) 2010 Isilon Systems, Inc.
* Copyright (c) 2010 iX Systems, Inc. * Copyright (c) 2010 iX Systems, Inc.
* Copyright (c) 2010 Panasas, Inc. * Copyright (c) 2010 Panasas, Inc.
* Copyright (c) 2013-2016 Mellanox Technologies, Ltd. * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -31,74 +31,27 @@
#ifndef _LINUX_KTHREAD_H_ #ifndef _LINUX_KTHREAD_H_
#define _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> #include <linux/sched.h>
static inline void #include <sys/unistd.h>
linux_kthread_fn(void *arg) #include <sys/kthread.h>
{
struct task_struct *task;
struct thread *td = curthread;
task = arg; #define kthread_run(fn, data, fmt, ...) ({ \
task_struct_fill(td, task); struct task_struct *__task; \
task_struct_set(td, task); struct thread *__td; \
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; \
\ \
_task = linux_kthread_create((fn), (data)); \ if (kthread_add(linux_kthread_fn, NULL, NULL, &__td, \
if (kthread_add(linux_kthread_fn, _task, NULL, &_task->task_thread, \ RFSTOPPED, 0, fmt, ## __VA_ARGS__)) \
0, 0, fmt, ## __VA_ARGS__)) { \ __task = NULL; \
kfree(_task); \ else \
_task = NULL; \ __task = linux_kthread_setup_and_run(__td, fn, data); \
} \ __task; \
_task; \
}) })
#define kthread_should_stop() current->should_stop extern int kthread_stop(struct task_struct *);
extern bool kthread_should_stop_task(struct task_struct *);
static inline int extern bool kthread_should_stop(void);
kthread_stop(struct task_struct *task) extern void linux_kthread_fn(void *);
{ extern struct task_struct *linux_kthread_setup_and_run(struct thread *, linux_task_fn_t *, void *arg);
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;
}
#endif /* _LINUX_KTHREAD_H_ */ #endif /* _LINUX_KTHREAD_H_ */

View File

@ -34,6 +34,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/lock.h> #include <sys/lock.h>
#include <sys/rwlock.h> #include <sys/rwlock.h>
#include <sys/libkern.h>
typedef struct { typedef struct {
struct rwlock rw; struct rwlock rw;

View File

@ -34,6 +34,7 @@
#include <sys/param.h> #include <sys/param.h>
#include <sys/lock.h> #include <sys/lock.h>
#include <sys/sx.h> #include <sys/sx.h>
#include <sys/libkern.h>
struct rw_semaphore { struct rw_semaphore {
struct sx sx; struct sx sx;

View File

@ -2,7 +2,7 @@
* Copyright (c) 2010 Isilon Systems, Inc. * Copyright (c) 2010 Isilon Systems, Inc.
* Copyright (c) 2010 iX Systems, Inc. * Copyright (c) 2010 iX Systems, Inc.
* Copyright (c) 2010 Panasas, Inc. * Copyright (c) 2010 Panasas, Inc.
* Copyright (c) 2013-2016 Mellanox Technologies, Ltd. * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -37,6 +37,12 @@
#include <sys/sched.h> #include <sys/sched.h>
#include <sys/sleepqueue.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 MAX_SCHEDULE_TIMEOUT LONG_MAX
#define TASK_RUNNING 0 #define TASK_RUNNING 0
@ -46,41 +52,22 @@
#define TASK_WAKEKILL 128 #define TASK_WAKEKILL 128
#define TASK_WAKING 256 #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 task_struct {
struct thread *task_thread; struct thread *task_thread;
int (*task_fn)(void *data); linux_task_fn_t *task_fn;
void *task_data; void *task_data;
int task_ret; int task_ret;
int state; int state;
int should_stop; atomic_t kthread_flags;
pid_t pid; pid_t pid;
const char *comm; const char *comm;
void *bsd_ioctl_data; void *bsd_ioctl_data;
unsigned bsd_ioctl_len; unsigned bsd_ioctl_len;
struct completion parked;
struct completion exited;
}; };
#define current task_struct_get(curthread) #define current ((struct task_struct *)curthread->td_lkpi_task)
#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 set_current_state(x) \ #define set_current_state(x) \
atomic_store_rel_int((volatile int *)&current->state, (x)) atomic_store_rel_int((volatile int *)&current->state, (x))

View File

@ -34,6 +34,7 @@
#include <sys/param.h> #include <sys/param.h>
#include <sys/lock.h> #include <sys/lock.h>
#include <sys/sema.h> #include <sys/sema.h>
#include <sys/libkern.h>
/* /*
* XXX BSD semaphores are disused and slow. They also do not provide a * 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/kernel.h>
#include <sys/lock.h> #include <sys/lock.h>
#include <sys/mutex.h> #include <sys/mutex.h>
#include <sys/libkern.h>
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/kernel.h>
#include <linux/rwlock.h> #include <linux/rwlock.h>
typedef struct { typedef struct {

View File

@ -63,4 +63,6 @@ typedef u64 phys_addr_t;
#define DECLARE_BITMAP(n, bits) \ #define DECLARE_BITMAP(n, bits) \
unsigned long n[howmany(bits, sizeof(long) * 8)] unsigned long n[howmany(bits, sizeof(long) * 8)]
typedef int linux_task_fn_t(void *data);
#endif /* _LINUX_TYPES_H_ */ #endif /* _LINUX_TYPES_H_ */

View File

@ -32,8 +32,6 @@
#define _LINUX_WAIT_H_ #define _LINUX_WAIT_H_
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/spinlock.h>
#include <linux/sched.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/jiffies.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); 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 static void
linux_file_dtor(void *cdp) linux_file_dtor(void *cdp)
{ {
struct linux_file *filp; struct linux_file *filp;
struct task_struct t;
struct thread *td;
td = curthread; linux_set_current(curthread);
filp = cdp; filp = cdp;
linux_set_current(td, &t);
filp->f_op->release(filp->f_vnode, filp); filp->f_op->release(filp->f_vnode, filp);
linux_clear_current(td);
vdrop(filp->f_vnode); vdrop(filp->f_vnode);
kfree(filp); 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_cdev *ldev;
struct linux_file *filp; struct linux_file *filp;
struct task_struct t;
struct file *file; struct file *file;
int error; 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; filp->f_flags = file->f_flag;
vhold(file->f_vnode); vhold(file->f_vnode);
filp->f_vnode = file->f_vnode; filp->f_vnode = file->f_vnode;
linux_set_current(td, &t); linux_set_current(td);
if (filp->f_op->open) { if (filp->f_op->open) {
error = -filp->f_op->open(file->f_vnode, filp); error = -filp->f_op->open(file->f_vnode, filp);
if (error) { if (error) {
@ -447,7 +428,6 @@ linux_dev_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
kfree(filp); kfree(filp);
} }
done: done:
linux_clear_current(td);
return (error); 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_cdev *ldev;
struct linux_file *filp; struct linux_file *filp;
struct task_struct t;
struct file *file; struct file *file;
unsigned size; unsigned size;
int error; 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) if ((error = devfs_get_cdevpriv((void **)&filp)) != 0)
return (error); return (error);
filp->f_flags = file->f_flag; filp->f_flags = file->f_flag;
linux_set_current(td, &t);
linux_set_current(td);
size = IOCPARM_LEN(cmd); size = IOCPARM_LEN(cmd);
/* refer to logic in sys_ioctl() */ /* refer to logic in sys_ioctl() */
if (size > 0) { 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 * Background: Linux code expects a user-space address
* while FreeBSD supplies a kernel-space address. * while FreeBSD supplies a kernel-space address.
*/ */
t.bsd_ioctl_data = data; current->bsd_ioctl_data = data;
t.bsd_ioctl_len = size; current->bsd_ioctl_len = size;
data = (void *)LINUX_IOCTL_MIN_PTR; data = (void *)LINUX_IOCTL_MIN_PTR;
} else { } else {
/* fetch user-space pointer */ /* 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); error = -filp->f_op->unlocked_ioctl(filp, cmd, (u_long)data);
else else
error = ENOTTY; error = ENOTTY;
linux_clear_current(td); if (size > 0) {
current->bsd_ioctl_data = NULL;
current->bsd_ioctl_len = 0;
}
return (error); return (error);
} }
@ -581,7 +564,6 @@ linux_dev_read(struct cdev *dev, struct uio *uio, int ioflag)
{ {
struct linux_cdev *ldev; struct linux_cdev *ldev;
struct linux_file *filp; struct linux_file *filp;
struct task_struct t;
struct thread *td; struct thread *td;
struct file *file; struct file *file;
ssize_t bytes; 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 */ /* XXX no support for I/O vectors currently */
if (uio->uio_iovcnt != 1) if (uio->uio_iovcnt != 1)
return (EOPNOTSUPP); return (EOPNOTSUPP);
linux_set_current(td, &t); linux_set_current(td);
if (filp->f_op->read) { if (filp->f_op->read) {
bytes = filp->f_op->read(filp, uio->uio_iov->iov_base, bytes = filp->f_op->read(filp, uio->uio_iov->iov_base,
uio->uio_iov->iov_len, &uio->uio_offset); 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; error = -bytes;
} else } else
error = ENXIO; error = ENXIO;
linux_clear_current(td);
return (error); return (error);
} }
@ -621,7 +602,6 @@ linux_dev_write(struct cdev *dev, struct uio *uio, int ioflag)
{ {
struct linux_cdev *ldev; struct linux_cdev *ldev;
struct linux_file *filp; struct linux_file *filp;
struct task_struct t;
struct thread *td; struct thread *td;
struct file *file; struct file *file;
ssize_t bytes; 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 */ /* XXX no support for I/O vectors currently */
if (uio->uio_iovcnt != 1) if (uio->uio_iovcnt != 1)
return (EOPNOTSUPP); return (EOPNOTSUPP);
linux_set_current(td, &t); linux_set_current(td);
if (filp->f_op->write) { if (filp->f_op->write) {
bytes = filp->f_op->write(filp, uio->uio_iov->iov_base, bytes = filp->f_op->write(filp, uio->uio_iov->iov_base,
uio->uio_iov->iov_len, &uio->uio_offset); 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; error = -bytes;
} else } else
error = ENXIO; error = ENXIO;
linux_clear_current(td);
return (error); return (error);
} }
@ -661,7 +640,6 @@ linux_dev_poll(struct cdev *dev, int events, struct thread *td)
{ {
struct linux_cdev *ldev; struct linux_cdev *ldev;
struct linux_file *filp; struct linux_file *filp;
struct task_struct t;
struct file *file; struct file *file;
int revents; int revents;
int error; 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) if ((error = devfs_get_cdevpriv((void **)&filp)) != 0)
return (error); return (error);
filp->f_flags = file->f_flag; filp->f_flags = file->f_flag;
linux_set_current(td, &t); linux_set_current(td);
if (filp->f_op->poll) if (filp->f_op->poll)
revents = filp->f_op->poll(filp, NULL) & events; revents = filp->f_op->poll(filp, NULL) & events;
else else
revents = 0; revents = 0;
linux_clear_current(td);
return (revents); return (revents);
} }
@ -690,7 +667,6 @@ linux_dev_mmap_single(struct cdev *dev, vm_ooffset_t *offset,
struct linux_cdev *ldev; struct linux_cdev *ldev;
struct linux_file *filp; struct linux_file *filp;
struct thread *td; struct thread *td;
struct task_struct t;
struct file *file; struct file *file;
struct vm_area_struct vma; struct vm_area_struct vma;
int error; 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) if ((error = devfs_get_cdevpriv((void **)&filp)) != 0)
return (error); return (error);
filp->f_flags = file->f_flag; filp->f_flags = file->f_flag;
linux_set_current(td, &t); linux_set_current(td);
vma.vm_start = 0; vma.vm_start = 0;
vma.vm_end = size; vma.vm_end = size;
vma.vm_pgoff = *offset / PAGE_SIZE; vma.vm_pgoff = *offset / PAGE_SIZE;
@ -735,7 +711,6 @@ linux_dev_mmap_single(struct cdev *dev, vm_ooffset_t *offset,
} else } else
error = ENODEV; error = ENODEV;
done: done:
linux_clear_current(td);
return (error); return (error);
} }
@ -756,7 +731,6 @@ linux_file_read(struct file *file, struct uio *uio, struct ucred *active_cred,
int flags, struct thread *td) int flags, struct thread *td)
{ {
struct linux_file *filp; struct linux_file *filp;
struct task_struct t;
ssize_t bytes; ssize_t bytes;
int error; 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 */ /* XXX no support for I/O vectors currently */
if (uio->uio_iovcnt != 1) if (uio->uio_iovcnt != 1)
return (EOPNOTSUPP); return (EOPNOTSUPP);
linux_set_current(td, &t); linux_set_current(td);
if (filp->f_op->read) { if (filp->f_op->read) {
bytes = filp->f_op->read(filp, uio->uio_iov->iov_base, bytes = filp->f_op->read(filp, uio->uio_iov->iov_base,
uio->uio_iov->iov_len, &uio->uio_offset); 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; error = -bytes;
} else } else
error = ENXIO; error = ENXIO;
linux_clear_current(td);
return (error); return (error);
} }
@ -789,17 +762,15 @@ linux_file_poll(struct file *file, int events, struct ucred *active_cred,
struct thread *td) struct thread *td)
{ {
struct linux_file *filp; struct linux_file *filp;
struct task_struct t;
int revents; int revents;
filp = (struct linux_file *)file->f_data; filp = (struct linux_file *)file->f_data;
filp->f_flags = file->f_flag; filp->f_flags = file->f_flag;
linux_set_current(td, &t); linux_set_current(td);
if (filp->f_op->poll) if (filp->f_op->poll)
revents = filp->f_op->poll(filp, NULL) & events; revents = filp->f_op->poll(filp, NULL) & events;
else else
revents = 0; revents = 0;
linux_clear_current(td);
return (revents); return (revents);
} }
@ -808,14 +779,12 @@ static int
linux_file_close(struct file *file, struct thread *td) linux_file_close(struct file *file, struct thread *td)
{ {
struct linux_file *filp; struct linux_file *filp;
struct task_struct t;
int error; int error;
filp = (struct linux_file *)file->f_data; filp = (struct linux_file *)file->f_data;
filp->f_flags = file->f_flag; filp->f_flags = file->f_flag;
linux_set_current(td, &t); linux_set_current(td);
error = -filp->f_op->release(NULL, filp); error = -filp->f_op->release(NULL, filp);
linux_clear_current(td);
funsetown(&filp->f_sigio); funsetown(&filp->f_sigio);
kfree(filp); kfree(filp);
@ -827,14 +796,13 @@ linux_file_ioctl(struct file *fp, u_long cmd, void *data, struct ucred *cred,
struct thread *td) struct thread *td)
{ {
struct linux_file *filp; struct linux_file *filp;
struct task_struct t;
int error; int error;
filp = (struct linux_file *)fp->f_data; filp = (struct linux_file *)fp->f_data;
filp->f_flags = fp->f_flag; filp->f_flags = fp->f_flag;
error = 0; error = 0;
linux_set_current(td, &t); linux_set_current(td);
switch (cmd) { switch (cmd) {
case FIONBIO: case FIONBIO:
break; break;
@ -856,7 +824,6 @@ linux_file_ioctl(struct file *fp, u_long cmd, void *data, struct ucred *cred,
error = ENOTTY; error = ENOTTY;
break; break;
} }
linux_clear_current(td);
return (error); 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_dev *pdev;
struct pci_driver *pdrv; struct pci_driver *pdrv;
const struct pci_device_id *id; const struct pci_device_id *id;
struct task_struct t;
struct thread *td;
int error; int error;
td = curthread; linux_set_current(curthread);
linux_set_current(td, &t);
pdrv = linux_pci_find(dev, &id); pdrv = linux_pci_find(dev, &id);
pdev = device_get_softc(dev); pdev = device_get_softc(dev);
pdev->dev.parent = &linux_root_device; pdev->dev.parent = &linux_root_device;
@ -159,7 +156,6 @@ linux_pci_attach(device_t dev)
put_device(&pdev->dev); put_device(&pdev->dev);
error = -error; error = -error;
} }
linux_clear_current(td);
return (error); return (error);
} }
@ -167,11 +163,8 @@ static int
linux_pci_detach(device_t dev) linux_pci_detach(device_t dev)
{ {
struct pci_dev *pdev; struct pci_dev *pdev;
struct task_struct t;
struct thread *td;
td = curthread; linux_set_current(curthread);
linux_set_current(td, &t);
pdev = device_get_softc(dev); pdev = device_get_softc(dev);
DROP_GIANT(); DROP_GIANT();
pdev->pdrv->remove(pdev); pdev->pdrv->remove(pdev);
@ -180,7 +173,6 @@ linux_pci_detach(device_t dev)
list_del(&pdev->links); list_del(&pdev->links);
spin_unlock(&pci_lock); spin_unlock(&pci_lock);
put_device(&pdev->dev); put_device(&pdev->dev);
linux_clear_current(td);
return (0); return (0);
} }
@ -190,18 +182,14 @@ linux_pci_suspend(device_t dev)
{ {
struct pm_message pm = { }; struct pm_message pm = { };
struct pci_dev *pdev; struct pci_dev *pdev;
struct task_struct t;
struct thread *td;
int err; int err;
td = curthread; linux_set_current(curthread);
linux_set_current(td, &t);
pdev = device_get_softc(dev); pdev = device_get_softc(dev);
if (pdev->pdrv->suspend != NULL) if (pdev->pdrv->suspend != NULL)
err = -pdev->pdrv->suspend(pdev, pm); err = -pdev->pdrv->suspend(pdev, pm);
else else
err = 0; err = 0;
linux_clear_current(td);
return (err); return (err);
} }
@ -209,18 +197,14 @@ static int
linux_pci_resume(device_t dev) linux_pci_resume(device_t dev)
{ {
struct pci_dev *pdev; struct pci_dev *pdev;
struct task_struct t;
struct thread *td;
int err; int err;
td = curthread; linux_set_current(curthread);
linux_set_current(td, &t);
pdev = device_get_softc(dev); pdev = device_get_softc(dev);
if (pdev->pdrv->resume != NULL) if (pdev->pdrv->resume != NULL)
err = -pdev->pdrv->resume(pdev); err = -pdev->pdrv->resume(pdev);
else else
err = 0; err = 0;
linux_clear_current(td);
return (err); return (err);
} }
@ -228,18 +212,14 @@ static int
linux_pci_shutdown(device_t dev) linux_pci_shutdown(device_t dev)
{ {
struct pci_dev *pdev; struct pci_dev *pdev;
struct task_struct t;
struct thread *td;
td = curthread; linux_set_current(curthread);
linux_set_current(td, &t);
pdev = device_get_softc(dev); pdev = device_get_softc(dev);
if (pdev->pdrv->shutdown != NULL) { if (pdev->pdrv->shutdown != NULL) {
DROP_GIANT(); DROP_GIANT();
pdev->pdrv->shutdown(pdev); pdev->pdrv->shutdown(pdev);
PICKUP_GIANT(); PICKUP_GIANT();
} }
linux_clear_current(td);
return (0); return (0);
} }
@ -251,6 +231,7 @@ pci_register_driver(struct pci_driver *pdrv)
bus = devclass_find("pci"); bus = devclass_find("pci");
linux_set_current(curthread);
spin_lock(&pci_lock); spin_lock(&pci_lock);
list_add(&pdrv->links, &pci_drivers); list_add(&pdrv->links, &pci_drivers);
spin_unlock(&pci_lock); spin_unlock(&pci_lock);

View File

@ -4266,6 +4266,10 @@ compat/linuxkpi/common/src/linux_kmod.c optional compat_linuxkpi \
compile-with "${LINUXKPI_C}" compile-with "${LINUXKPI_C}"
compat/linuxkpi/common/src/linux_compat.c optional compat_linuxkpi \ compat/linuxkpi/common/src/linux_compat.c optional compat_linuxkpi \
compile-with "${LINUXKPI_C}" 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 \ compat/linuxkpi/common/src/linux_pci.c optional compat_linuxkpi pci \
compile-with "${LINUXKPI_C}" compile-with "${LINUXKPI_C}"
compat/linuxkpi/common/src/linux_idr.c optional compat_linuxkpi \ compat/linuxkpi/common/src/linux_idr.c optional compat_linuxkpi \

View File

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

View File

@ -58,7 +58,7 @@
* in the range 5 to 9. * in the range 5 to 9.
*/ */
#undef __FreeBSD_version #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, * __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 */ void *td_emuldata; /* Emulator state data */
int td_lastcpu; /* (t) Last cpu we were on. */ int td_lastcpu; /* (t) Last cpu we were on. */
int td_oncpu; /* (t) Which cpu we are on. */ int td_oncpu; /* (t) Which cpu we are on. */
void *td_lkpi_task; /* LinuxKPI task struct pointer */
}; };
struct thread0_storage { struct thread0_storage {