Create a dummy "task_struct" on the stack which is returned by
"current" inside all LinuxKPI file operation callbacks. The "current" is frequently used for various debug prints, printing the thread name and thread ID for example. Obtained from: kmacy @ MFC after: 1 week Sponsored by: Mellanox Technologies
This commit is contained in:
parent
dc77866517
commit
464d20bcc8
@ -2,7 +2,7 @@
|
||||
* Copyright (c) 2010 Isilon Systems, Inc.
|
||||
* Copyright (c) 2010 iX Systems, Inc.
|
||||
* Copyright (c) 2010 Panasas, Inc.
|
||||
* Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
|
||||
* Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -45,15 +45,18 @@ static inline void
|
||||
linux_kthread_fn(void *arg)
|
||||
{
|
||||
struct task_struct *task;
|
||||
struct thread *td = curthread;
|
||||
|
||||
task = arg;
|
||||
task_struct_set(curthread, task);
|
||||
task_struct_fill(td, task);
|
||||
task_struct_set(td, task);
|
||||
if (task->should_stop == 0)
|
||||
task->task_ret = task->task_fn(task->task_data);
|
||||
PROC_LOCK(task->task_thread->td_proc);
|
||||
PROC_LOCK(td->td_proc);
|
||||
task->should_stop = TASK_STOPPED;
|
||||
wakeup(task);
|
||||
PROC_UNLOCK(task->task_thread->td_proc);
|
||||
PROC_UNLOCK(td->td_proc);
|
||||
task_struct_set(td, NULL);
|
||||
kthread_exit();
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
* Copyright (c) 2010 Isilon Systems, Inc.
|
||||
* Copyright (c) 2010 iX Systems, Inc.
|
||||
* Copyright (c) 2010 Panasas, Inc.
|
||||
* Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
|
||||
* Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -50,10 +50,12 @@
|
||||
#define TASK_STOPPED 2
|
||||
|
||||
/*
|
||||
* A task_struct is only provided for those tasks created with kthread.
|
||||
* Using these routines with threads not started via kthread will cause
|
||||
* panics because no task_struct is allocated and td_retval[1] is
|
||||
* overwritten by syscalls which kernel threads will not make use of.
|
||||
* A task_struct is only provided for threads created by kthread() and
|
||||
* file operation callbacks.
|
||||
*
|
||||
* Using these routines outside the above mentioned contexts will
|
||||
* cause panics because no task_struct is assigned and td_retval[1] is
|
||||
* overwritten by syscalls.
|
||||
*/
|
||||
struct task_struct {
|
||||
struct thread *task_thread;
|
||||
@ -62,10 +64,17 @@ struct task_struct {
|
||||
int task_ret;
|
||||
int state;
|
||||
int should_stop;
|
||||
pid_t pid;
|
||||
const char *comm;
|
||||
};
|
||||
|
||||
#define current task_struct_get(curthread)
|
||||
#define task_struct_get(x) ((struct task_struct *)(uintptr_t)(x)->td_retval[1])
|
||||
#define task_struct_fill(x, y) do { \
|
||||
(y)->task_thread = (x); \
|
||||
(y)->comm = (x)->td_name; \
|
||||
(y)->pid = (x)->td_tid; \
|
||||
} while (0)
|
||||
#define task_struct_set(x, y) (x)->td_retval[1] = (uintptr_t)(y)
|
||||
|
||||
/* ensure the task_struct pointer fits into the td_retval[1] field */
|
||||
|
@ -373,13 +373,32 @@ kobject_init_and_add(struct kobject *kobj, const struct kobj_type *ktype,
|
||||
return kobject_add_complete(kobj, parent);
|
||||
}
|
||||
|
||||
static void
|
||||
linux_set_current(struct thread *td, struct task_struct *t)
|
||||
{
|
||||
memset(t, 0, sizeof(*t));
|
||||
task_struct_fill(td, t);
|
||||
task_struct_set(td, t);
|
||||
}
|
||||
|
||||
static void
|
||||
linux_clear_current(struct thread *td)
|
||||
{
|
||||
task_struct_set(td, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
linux_file_dtor(void *cdp)
|
||||
{
|
||||
struct linux_file *filp;
|
||||
struct task_struct t;
|
||||
struct thread *td;
|
||||
|
||||
td = curthread;
|
||||
filp = cdp;
|
||||
linux_set_current(td, &t);
|
||||
filp->f_op->release(filp->f_vnode, filp);
|
||||
linux_clear_current(td);
|
||||
vdrop(filp->f_vnode);
|
||||
kfree(filp);
|
||||
}
|
||||
@ -389,10 +408,11 @@ linux_dev_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
|
||||
{
|
||||
struct linux_cdev *ldev;
|
||||
struct linux_file *filp;
|
||||
struct task_struct t;
|
||||
struct file *file;
|
||||
int error;
|
||||
|
||||
file = curthread->td_fpop;
|
||||
file = td->td_fpop;
|
||||
ldev = dev->si_drv1;
|
||||
if (ldev == NULL)
|
||||
return (ENODEV);
|
||||
@ -402,21 +422,22 @@ linux_dev_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
|
||||
filp->f_flags = file->f_flag;
|
||||
vhold(file->f_vnode);
|
||||
filp->f_vnode = file->f_vnode;
|
||||
linux_set_current(td, &t);
|
||||
if (filp->f_op->open) {
|
||||
error = -filp->f_op->open(file->f_vnode, filp);
|
||||
if (error) {
|
||||
kfree(filp);
|
||||
return (error);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
error = devfs_set_cdevpriv(filp, linux_file_dtor);
|
||||
if (error) {
|
||||
filp->f_op->release(file->f_vnode, filp);
|
||||
kfree(filp);
|
||||
return (error);
|
||||
}
|
||||
|
||||
return 0;
|
||||
done:
|
||||
linux_clear_current(td);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -427,7 +448,7 @@ linux_dev_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
|
||||
struct file *file;
|
||||
int error;
|
||||
|
||||
file = curthread->td_fpop;
|
||||
file = td->td_fpop;
|
||||
ldev = dev->si_drv1;
|
||||
if (ldev == NULL)
|
||||
return (0);
|
||||
@ -446,16 +467,18 @@ linux_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
|
||||
{
|
||||
struct linux_cdev *ldev;
|
||||
struct linux_file *filp;
|
||||
struct task_struct t;
|
||||
struct file *file;
|
||||
int error;
|
||||
|
||||
file = curthread->td_fpop;
|
||||
file = td->td_fpop;
|
||||
ldev = dev->si_drv1;
|
||||
if (ldev == NULL)
|
||||
return (0);
|
||||
if ((error = devfs_get_cdevpriv((void **)&filp)) != 0)
|
||||
return (error);
|
||||
filp->f_flags = file->f_flag;
|
||||
linux_set_current(td, &t);
|
||||
/*
|
||||
* Linux does not have a generic ioctl copyin/copyout layer. All
|
||||
* linux ioctls must be converted to void ioctls which pass a
|
||||
@ -467,6 +490,7 @@ linux_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
|
||||
error = -filp->f_op->unlocked_ioctl(filp, cmd, (u_long)data);
|
||||
else
|
||||
error = ENOTTY;
|
||||
linux_clear_current(td);
|
||||
|
||||
return (error);
|
||||
}
|
||||
@ -476,11 +500,14 @@ linux_dev_read(struct cdev *dev, struct uio *uio, int ioflag)
|
||||
{
|
||||
struct linux_cdev *ldev;
|
||||
struct linux_file *filp;
|
||||
struct task_struct t;
|
||||
struct thread *td;
|
||||
struct file *file;
|
||||
ssize_t bytes;
|
||||
int error;
|
||||
|
||||
file = curthread->td_fpop;
|
||||
td = curthread;
|
||||
file = td->td_fpop;
|
||||
ldev = dev->si_drv1;
|
||||
if (ldev == NULL)
|
||||
return (0);
|
||||
@ -490,6 +517,7 @@ linux_dev_read(struct cdev *dev, struct uio *uio, int ioflag)
|
||||
/* XXX no support for I/O vectors currently */
|
||||
if (uio->uio_iovcnt != 1)
|
||||
return (EOPNOTSUPP);
|
||||
linux_set_current(td, &t);
|
||||
if (filp->f_op->read) {
|
||||
bytes = filp->f_op->read(filp, uio->uio_iov->iov_base,
|
||||
uio->uio_iov->iov_len, &uio->uio_offset);
|
||||
@ -502,6 +530,7 @@ linux_dev_read(struct cdev *dev, struct uio *uio, int ioflag)
|
||||
error = -bytes;
|
||||
} else
|
||||
error = ENXIO;
|
||||
linux_clear_current(td);
|
||||
|
||||
return (error);
|
||||
}
|
||||
@ -511,11 +540,14 @@ linux_dev_write(struct cdev *dev, struct uio *uio, int ioflag)
|
||||
{
|
||||
struct linux_cdev *ldev;
|
||||
struct linux_file *filp;
|
||||
struct task_struct t;
|
||||
struct thread *td;
|
||||
struct file *file;
|
||||
ssize_t bytes;
|
||||
int error;
|
||||
|
||||
file = curthread->td_fpop;
|
||||
td = curthread;
|
||||
file = td->td_fpop;
|
||||
ldev = dev->si_drv1;
|
||||
if (ldev == NULL)
|
||||
return (0);
|
||||
@ -525,6 +557,7 @@ linux_dev_write(struct cdev *dev, struct uio *uio, int ioflag)
|
||||
/* XXX no support for I/O vectors currently */
|
||||
if (uio->uio_iovcnt != 1)
|
||||
return (EOPNOTSUPP);
|
||||
linux_set_current(td, &t);
|
||||
if (filp->f_op->write) {
|
||||
bytes = filp->f_op->write(filp, uio->uio_iov->iov_base,
|
||||
uio->uio_iov->iov_len, &uio->uio_offset);
|
||||
@ -537,6 +570,7 @@ linux_dev_write(struct cdev *dev, struct uio *uio, int ioflag)
|
||||
error = -bytes;
|
||||
} else
|
||||
error = ENXIO;
|
||||
linux_clear_current(td);
|
||||
|
||||
return (error);
|
||||
}
|
||||
@ -546,21 +580,24 @@ linux_dev_poll(struct cdev *dev, int events, struct thread *td)
|
||||
{
|
||||
struct linux_cdev *ldev;
|
||||
struct linux_file *filp;
|
||||
struct task_struct t;
|
||||
struct file *file;
|
||||
int revents;
|
||||
int error;
|
||||
|
||||
file = curthread->td_fpop;
|
||||
file = td->td_fpop;
|
||||
ldev = dev->si_drv1;
|
||||
if (ldev == NULL)
|
||||
return (0);
|
||||
if ((error = devfs_get_cdevpriv((void **)&filp)) != 0)
|
||||
return (error);
|
||||
filp->f_flags = file->f_flag;
|
||||
linux_set_current(td, &t);
|
||||
if (filp->f_op->poll)
|
||||
revents = filp->f_op->poll(filp, NULL) & events;
|
||||
else
|
||||
revents = 0;
|
||||
linux_clear_current(td);
|
||||
|
||||
return (revents);
|
||||
}
|
||||
@ -571,17 +608,21 @@ linux_dev_mmap_single(struct cdev *dev, vm_ooffset_t *offset,
|
||||
{
|
||||
struct linux_cdev *ldev;
|
||||
struct linux_file *filp;
|
||||
struct thread *td;
|
||||
struct task_struct t;
|
||||
struct file *file;
|
||||
struct vm_area_struct vma;
|
||||
int error;
|
||||
|
||||
file = curthread->td_fpop;
|
||||
td = curthread;
|
||||
file = td->td_fpop;
|
||||
ldev = dev->si_drv1;
|
||||
if (ldev == NULL)
|
||||
return (ENODEV);
|
||||
if ((error = devfs_get_cdevpriv((void **)&filp)) != 0)
|
||||
return (error);
|
||||
filp->f_flags = file->f_flag;
|
||||
linux_set_current(td, &t);
|
||||
vma.vm_start = 0;
|
||||
vma.vm_end = size;
|
||||
vma.vm_pgoff = *offset / PAGE_SIZE;
|
||||
@ -596,10 +637,11 @@ linux_dev_mmap_single(struct cdev *dev, vm_ooffset_t *offset,
|
||||
sglist_append_phys(sg,
|
||||
(vm_paddr_t)vma.vm_pfn << PAGE_SHIFT, vma.vm_len);
|
||||
*object = vm_pager_allocate(OBJT_SG, sg, vma.vm_len,
|
||||
nprot, 0, curthread->td_ucred);
|
||||
nprot, 0, td->td_ucred);
|
||||
if (*object == NULL) {
|
||||
sglist_free(sg);
|
||||
return (EINVAL);
|
||||
error = EINVAL;
|
||||
goto done;
|
||||
}
|
||||
*offset = 0;
|
||||
if (vma.vm_page_prot != VM_MEMATTR_DEFAULT) {
|
||||
@ -611,7 +653,8 @@ linux_dev_mmap_single(struct cdev *dev, vm_ooffset_t *offset,
|
||||
}
|
||||
} else
|
||||
error = ENODEV;
|
||||
|
||||
done:
|
||||
linux_clear_current(td);
|
||||
return (error);
|
||||
}
|
||||
|
||||
@ -632,6 +675,7 @@ linux_file_read(struct file *file, struct uio *uio, struct ucred *active_cred,
|
||||
int flags, struct thread *td)
|
||||
{
|
||||
struct linux_file *filp;
|
||||
struct task_struct t;
|
||||
ssize_t bytes;
|
||||
int error;
|
||||
|
||||
@ -641,6 +685,7 @@ linux_file_read(struct file *file, struct uio *uio, struct ucred *active_cred,
|
||||
/* XXX no support for I/O vectors currently */
|
||||
if (uio->uio_iovcnt != 1)
|
||||
return (EOPNOTSUPP);
|
||||
linux_set_current(td, &t);
|
||||
if (filp->f_op->read) {
|
||||
bytes = filp->f_op->read(filp, uio->uio_iov->iov_base,
|
||||
uio->uio_iov->iov_len, &uio->uio_offset);
|
||||
@ -653,6 +698,7 @@ linux_file_read(struct file *file, struct uio *uio, struct ucred *active_cred,
|
||||
error = -bytes;
|
||||
} else
|
||||
error = ENXIO;
|
||||
linux_clear_current(td);
|
||||
|
||||
return (error);
|
||||
}
|
||||
@ -662,14 +708,17 @@ linux_file_poll(struct file *file, int events, struct ucred *active_cred,
|
||||
struct thread *td)
|
||||
{
|
||||
struct linux_file *filp;
|
||||
struct task_struct t;
|
||||
int revents;
|
||||
|
||||
filp = (struct linux_file *)file->f_data;
|
||||
filp->f_flags = file->f_flag;
|
||||
linux_set_current(td, &t);
|
||||
if (filp->f_op->poll)
|
||||
revents = filp->f_op->poll(filp, NULL) & events;
|
||||
else
|
||||
revents = 0;
|
||||
linux_clear_current(td);
|
||||
|
||||
return (revents);
|
||||
}
|
||||
@ -678,11 +727,14 @@ static int
|
||||
linux_file_close(struct file *file, struct thread *td)
|
||||
{
|
||||
struct linux_file *filp;
|
||||
struct task_struct t;
|
||||
int error;
|
||||
|
||||
filp = (struct linux_file *)file->f_data;
|
||||
filp->f_flags = file->f_flag;
|
||||
linux_set_current(td, &t);
|
||||
error = -filp->f_op->release(NULL, filp);
|
||||
linux_clear_current(td);
|
||||
funsetown(&filp->f_sigio);
|
||||
kfree(filp);
|
||||
|
||||
@ -694,12 +746,14 @@ linux_file_ioctl(struct file *fp, u_long cmd, void *data, struct ucred *cred,
|
||||
struct thread *td)
|
||||
{
|
||||
struct linux_file *filp;
|
||||
struct task_struct t;
|
||||
int error;
|
||||
|
||||
filp = (struct linux_file *)fp->f_data;
|
||||
filp->f_flags = fp->f_flag;
|
||||
error = 0;
|
||||
|
||||
linux_set_current(td, &t);
|
||||
switch (cmd) {
|
||||
case FIONBIO:
|
||||
break;
|
||||
@ -721,6 +775,7 @@ linux_file_ioctl(struct file *fp, u_long cmd, void *data, struct ucred *cred,
|
||||
error = ENOTTY;
|
||||
break;
|
||||
}
|
||||
linux_clear_current(td);
|
||||
return (error);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user