Fixes for the LinuxAPI completion wrappers:
- make sure the timeout computations are always above zero by using the existing "linux_timer_jiffies_until()" function. Negative timeouts can result in undefined behaviour. - declare all completion functions like external symbols and move the code to the LinuxAPI kernel module. - add a proper prefix to all LinuxAPI kernel functions to avoid namespace collision with other parts of the FreeBSD kernel. - clean up header file inclusions in the linux/completion.h, linux/in.h and linux/fs.h header files. MFC after: 1 week Sponsored by: Mellanox Technologies
This commit is contained in:
parent
9928931186
commit
932493ff29
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=280764
@ -32,124 +32,35 @@
|
||||
|
||||
#include <linux/errno.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/sleepqueue.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/proc.h>
|
||||
|
||||
struct completion {
|
||||
unsigned int done;
|
||||
};
|
||||
|
||||
#define INIT_COMPLETION(c) ((c).done = 0)
|
||||
#define init_completion(c) ((c)->done = 0)
|
||||
#define INIT_COMPLETION(c) \
|
||||
((c).done = 0)
|
||||
#define init_completion(c) \
|
||||
((c)->done = 0)
|
||||
#define complete(c) \
|
||||
linux_complete_common((c), 0)
|
||||
#define complete_all(c) \
|
||||
linux_complete_common((c), 1)
|
||||
#define wait_for_completion(c) \
|
||||
linux_wait_for_common((c), 0)
|
||||
#define wait_for_completion_interuptible(c) \
|
||||
linux_wait_for_common((c), 1)
|
||||
#define wait_for_completion_timeout(c, timeout) \
|
||||
linux_wait_for_timeout_common((c), (timeout), 0)
|
||||
#define wait_for_completion_interruptible_timeout(c, timeout) \
|
||||
linux_wait_for_timeout_common((c), (timeout), 1)
|
||||
#define try_wait_for_completion(c) \
|
||||
linux_try_wait_for_completion(c)
|
||||
#define completion_done(c) \
|
||||
linux_completion_done(c)
|
||||
|
||||
static inline void
|
||||
_complete_common(struct completion *c, int all)
|
||||
{
|
||||
int wakeup_swapper;
|
||||
extern void linux_complete_common(struct completion *, int);
|
||||
extern long linux_wait_for_common(struct completion *, int);
|
||||
extern long linux_wait_for_timeout_common(struct completion *, long, int);
|
||||
extern int linux_try_wait_for_completion(struct completion *);
|
||||
extern int linux_completion_done(struct completion *);
|
||||
|
||||
sleepq_lock(c);
|
||||
c->done++;
|
||||
if (all)
|
||||
wakeup_swapper = sleepq_broadcast(c, SLEEPQ_SLEEP, 0, 0);
|
||||
else
|
||||
wakeup_swapper = sleepq_signal(c, SLEEPQ_SLEEP, 0, 0);
|
||||
sleepq_release(c);
|
||||
if (wakeup_swapper)
|
||||
kick_proc0();
|
||||
}
|
||||
|
||||
#define complete(c) _complete_common(c, 0)
|
||||
#define complete_all(c) _complete_common(c, 1)
|
||||
|
||||
/*
|
||||
* Indefinite wait for done != 0 with or without signals.
|
||||
*/
|
||||
static inline long
|
||||
_wait_for_common(struct completion *c, int flags)
|
||||
{
|
||||
|
||||
flags |= SLEEPQ_SLEEP;
|
||||
for (;;) {
|
||||
sleepq_lock(c);
|
||||
if (c->done)
|
||||
break;
|
||||
sleepq_add(c, NULL, "completion", flags, 0);
|
||||
if (flags & SLEEPQ_INTERRUPTIBLE) {
|
||||
if (sleepq_wait_sig(c, 0) != 0)
|
||||
return (-ERESTARTSYS);
|
||||
} else
|
||||
sleepq_wait(c, 0);
|
||||
}
|
||||
c->done--;
|
||||
sleepq_release(c);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
#define wait_for_completion(c) _wait_for_common(c, 0)
|
||||
#define wait_for_completion_interuptible(c) \
|
||||
_wait_for_common(c, SLEEPQ_INTERRUPTIBLE)
|
||||
|
||||
static inline long
|
||||
_wait_for_timeout_common(struct completion *c, long timeout, int flags)
|
||||
{
|
||||
long end;
|
||||
|
||||
end = ticks + timeout;
|
||||
flags |= SLEEPQ_SLEEP;
|
||||
for (;;) {
|
||||
sleepq_lock(c);
|
||||
if (c->done)
|
||||
break;
|
||||
sleepq_add(c, NULL, "completion", flags, 0);
|
||||
sleepq_set_timeout(c, end - ticks);
|
||||
if (flags & SLEEPQ_INTERRUPTIBLE) {
|
||||
if (sleepq_timedwait_sig(c, 0) != 0)
|
||||
return (-ERESTARTSYS);
|
||||
} else
|
||||
sleepq_timedwait(c, 0);
|
||||
}
|
||||
c->done--;
|
||||
sleepq_release(c);
|
||||
timeout = end - ticks;
|
||||
|
||||
return (timeout > 0 ? timeout : 1);
|
||||
}
|
||||
|
||||
#define wait_for_completion_timeout(c, timeout) \
|
||||
_wait_for_timeout_common(c, timeout, 0)
|
||||
#define wait_for_completion_interruptible_timeout(c, timeout) \
|
||||
_wait_for_timeout_common(c, timeout, SLEEPQ_INTERRUPTIBLE)
|
||||
|
||||
static inline int
|
||||
try_wait_for_completion(struct completion *c)
|
||||
{
|
||||
int isdone;
|
||||
|
||||
isdone = 1;
|
||||
sleepq_lock(c);
|
||||
if (c->done)
|
||||
c->done--;
|
||||
else
|
||||
isdone = 0;
|
||||
sleepq_release(c);
|
||||
return (isdone);
|
||||
}
|
||||
|
||||
static inline int
|
||||
completion_done(struct completion *c)
|
||||
{
|
||||
int isdone;
|
||||
|
||||
isdone = 1;
|
||||
sleepq_lock(c);
|
||||
if (c->done == 0)
|
||||
isdone = 0;
|
||||
sleepq_release(c);
|
||||
return (isdone);
|
||||
}
|
||||
|
||||
#endif /* _LINUX_COMPLETION_H_ */
|
||||
#endif /* _LINUX_COMPLETION_H_ */
|
||||
|
@ -29,6 +29,8 @@
|
||||
#ifndef _LINUX_FS_H_
|
||||
#define _LINUX_FS_H_
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/vnode.h>
|
||||
|
@ -31,6 +31,9 @@
|
||||
|
||||
#include "opt_inet.h"
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <netinet/in.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
|
@ -32,6 +32,8 @@
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/sleepqueue.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/bus.h>
|
||||
@ -781,6 +783,117 @@ linux_timer_init(void *arg)
|
||||
}
|
||||
SYSINIT(linux_timer, SI_SUB_DRIVERS, SI_ORDER_FIRST, linux_timer_init, NULL);
|
||||
|
||||
void
|
||||
linux_complete_common(struct completion *c, int all)
|
||||
{
|
||||
int wakeup_swapper;
|
||||
|
||||
sleepq_lock(c);
|
||||
c->done++;
|
||||
if (all)
|
||||
wakeup_swapper = sleepq_broadcast(c, SLEEPQ_SLEEP, 0, 0);
|
||||
else
|
||||
wakeup_swapper = sleepq_signal(c, SLEEPQ_SLEEP, 0, 0);
|
||||
sleepq_release(c);
|
||||
if (wakeup_swapper)
|
||||
kick_proc0();
|
||||
}
|
||||
|
||||
/*
|
||||
* Indefinite wait for done != 0 with or without signals.
|
||||
*/
|
||||
long
|
||||
linux_wait_for_common(struct completion *c, int flags)
|
||||
{
|
||||
|
||||
if (flags != 0)
|
||||
flags = SLEEPQ_INTERRUPTIBLE | SLEEPQ_SLEEP;
|
||||
else
|
||||
flags = SLEEPQ_SLEEP;
|
||||
for (;;) {
|
||||
sleepq_lock(c);
|
||||
if (c->done)
|
||||
break;
|
||||
sleepq_add(c, NULL, "completion", flags, 0);
|
||||
if (flags & SLEEPQ_INTERRUPTIBLE) {
|
||||
if (sleepq_wait_sig(c, 0) != 0)
|
||||
return (-ERESTARTSYS);
|
||||
} else
|
||||
sleepq_wait(c, 0);
|
||||
}
|
||||
c->done--;
|
||||
sleepq_release(c);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Time limited wait for done != 0 with or without signals.
|
||||
*/
|
||||
long
|
||||
linux_wait_for_timeout_common(struct completion *c, long timeout, int flags)
|
||||
{
|
||||
long end = jiffies + timeout;
|
||||
|
||||
if (flags != 0)
|
||||
flags = SLEEPQ_INTERRUPTIBLE | SLEEPQ_SLEEP;
|
||||
else
|
||||
flags = SLEEPQ_SLEEP;
|
||||
for (;;) {
|
||||
int ret;
|
||||
|
||||
sleepq_lock(c);
|
||||
if (c->done)
|
||||
break;
|
||||
sleepq_add(c, NULL, "completion", flags, 0);
|
||||
sleepq_set_timeout(c, linux_timer_jiffies_until(end));
|
||||
if (flags & SLEEPQ_INTERRUPTIBLE)
|
||||
ret = sleepq_timedwait_sig(c, 0);
|
||||
else
|
||||
ret = sleepq_timedwait(c, 0);
|
||||
if (ret != 0) {
|
||||
/* check for timeout or signal */
|
||||
if (ret == EWOULDBLOCK)
|
||||
return (0);
|
||||
else
|
||||
return (-ERESTARTSYS);
|
||||
}
|
||||
}
|
||||
c->done--;
|
||||
sleepq_release(c);
|
||||
|
||||
/* return how many jiffies are left */
|
||||
return (linux_timer_jiffies_until(end));
|
||||
}
|
||||
|
||||
int
|
||||
linux_try_wait_for_completion(struct completion *c)
|
||||
{
|
||||
int isdone;
|
||||
|
||||
isdone = 1;
|
||||
sleepq_lock(c);
|
||||
if (c->done)
|
||||
c->done--;
|
||||
else
|
||||
isdone = 0;
|
||||
sleepq_release(c);
|
||||
return (isdone);
|
||||
}
|
||||
|
||||
int
|
||||
linux_completion_done(struct completion *c)
|
||||
{
|
||||
int isdone;
|
||||
|
||||
isdone = 1;
|
||||
sleepq_lock(c);
|
||||
if (c->done == 0)
|
||||
isdone = 0;
|
||||
sleepq_release(c);
|
||||
return (isdone);
|
||||
}
|
||||
|
||||
static void
|
||||
linux_compat_init(void *arg)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user