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:
Hans Petter Selasky 2015-03-27 16:16:23 +00:00
parent 9928931186
commit 932493ff29
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=280764
4 changed files with 144 additions and 115 deletions

View File

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

View File

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

View File

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

View File

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