Add cv_timedwait_io()

Add missing helper function cv_timedwait_io(), it should be used
when waiting on IO with a specified timeout.

Reviewed-by: Tim Chase <tim@chase2k.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #674
This commit is contained in:
Brian Behlendorf 2018-01-24 11:33:47 -08:00 committed by GitHub
parent fb79036f28
commit 23602fdb39
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 73 additions and 8 deletions

View File

@ -52,6 +52,7 @@ AC_DEFUN([SPL_AC_CONFIG_KERNEL], [
SPL_AC_KMEM_CACHE_CREATE_USERCOPY SPL_AC_KMEM_CACHE_CREATE_USERCOPY
SPL_AC_WAIT_QUEUE_ENTRY_T SPL_AC_WAIT_QUEUE_ENTRY_T
SPL_AC_WAIT_QUEUE_HEAD_ENTRY SPL_AC_WAIT_QUEUE_HEAD_ENTRY
SPL_AC_IO_SCHEDULE_TIMEOUT
SPL_AC_KERNEL_WRITE SPL_AC_KERNEL_WRITE
SPL_AC_KERNEL_READ SPL_AC_KERNEL_READ
SPL_AC_KERNEL_TIMER_FUNCTION_TIMER_LIST SPL_AC_KERNEL_TIMER_FUNCTION_TIMER_LIST
@ -1598,6 +1599,26 @@ AC_DEFUN([SPL_AC_WAIT_QUEUE_HEAD_ENTRY], [
]) ])
]) ])
dnl #
dnl # 3.19 API change
dnl # The io_schedule_timeout() function is present in all 2.6.32 kernels
dnl # but it was not exported until Linux 3.19. The RHEL 7.x kernels which
dnl # are based on a 3.10 kernel do export this symbol.
dnl #
AC_DEFUN([SPL_AC_IO_SCHEDULE_TIMEOUT], [
AC_MSG_CHECKING([whether io_schedule_timeout() is available])
SPL_LINUX_TRY_COMPILE_SYMBOL([
#include <linux/sched.h>
], [
(void) io_schedule_timeout(1);
], [io_schedule_timeout], [], [
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_IO_SCHEDULE_TIMEOUT, 1, [yes])
],[
AC_MSG_RESULT(no)
])
])
dnl # dnl #
dnl # 4.14 API change dnl # 4.14 API change
dnl # kernel_write() which was introduced in 3.9 was updated to take dnl # kernel_write() which was introduced in 3.9 was updated to take

View File

@ -56,6 +56,7 @@ extern void __cv_wait(kcondvar_t *, kmutex_t *);
extern void __cv_wait_io(kcondvar_t *, kmutex_t *); extern void __cv_wait_io(kcondvar_t *, kmutex_t *);
extern void __cv_wait_sig(kcondvar_t *, kmutex_t *); extern void __cv_wait_sig(kcondvar_t *, kmutex_t *);
extern clock_t __cv_timedwait(kcondvar_t *, kmutex_t *, clock_t); extern clock_t __cv_timedwait(kcondvar_t *, kmutex_t *, clock_t);
extern clock_t __cv_timedwait_io(kcondvar_t *, kmutex_t *, clock_t);
extern clock_t __cv_timedwait_sig(kcondvar_t *, kmutex_t *, clock_t); extern clock_t __cv_timedwait_sig(kcondvar_t *, kmutex_t *, clock_t);
extern clock_t cv_timedwait_hires(kcondvar_t *, kmutex_t *, hrtime_t, extern clock_t cv_timedwait_hires(kcondvar_t *, kmutex_t *, hrtime_t,
hrtime_t res, int flag); hrtime_t res, int flag);
@ -71,6 +72,7 @@ extern void __cv_broadcast(kcondvar_t *c);
#define cv_wait_sig(cvp, mp) __cv_wait_sig(cvp, mp) #define cv_wait_sig(cvp, mp) __cv_wait_sig(cvp, mp)
#define cv_wait_interruptible(cvp, mp) cv_wait_sig(cvp, mp) #define cv_wait_interruptible(cvp, mp) cv_wait_sig(cvp, mp)
#define cv_timedwait(cvp, mp, t) __cv_timedwait(cvp, mp, t) #define cv_timedwait(cvp, mp, t) __cv_timedwait(cvp, mp, t)
#define cv_timedwait_io(cvp, mp, t) __cv_timedwait_io(cvp, mp, t)
#define cv_timedwait_sig(cvp, mp, t) __cv_timedwait_sig(cvp, mp, t) #define cv_timedwait_sig(cvp, mp, t) __cv_timedwait_sig(cvp, mp, t)
#define cv_timedwait_interruptible(cvp, mp, t) cv_timedwait_sig(cvp, mp, t) #define cv_timedwait_interruptible(cvp, mp, t) cv_timedwait_sig(cvp, mp, t)
#define cv_signal(cvp) __cv_signal(cvp) #define cv_signal(cvp) __cv_signal(cvp)

View File

@ -136,6 +136,13 @@ __cv_wait(kcondvar_t *cvp, kmutex_t *mp)
} }
EXPORT_SYMBOL(__cv_wait); EXPORT_SYMBOL(__cv_wait);
void
__cv_wait_io(kcondvar_t *cvp, kmutex_t *mp)
{
cv_wait_common(cvp, mp, TASK_UNINTERRUPTIBLE, 1);
}
EXPORT_SYMBOL(__cv_wait_io);
void void
__cv_wait_sig(kcondvar_t *cvp, kmutex_t *mp) __cv_wait_sig(kcondvar_t *cvp, kmutex_t *mp)
{ {
@ -143,12 +150,34 @@ __cv_wait_sig(kcondvar_t *cvp, kmutex_t *mp)
} }
EXPORT_SYMBOL(__cv_wait_sig); EXPORT_SYMBOL(__cv_wait_sig);
void #if defined(HAVE_IO_SCHEDULE_TIMEOUT)
__cv_wait_io(kcondvar_t *cvp, kmutex_t *mp) #define spl_io_schedule_timeout(t) io_schedule_timeout(t)
#else
static void
__cv_wakeup(unsigned long data)
{ {
cv_wait_common(cvp, mp, TASK_UNINTERRUPTIBLE, 1); wake_up_process((struct task_struct *)data);
} }
EXPORT_SYMBOL(__cv_wait_io);
static long
spl_io_schedule_timeout(long time_left)
{
long expire_time = jiffies + time_left;
struct timer_list timer;
init_timer(&timer);
setup_timer(&timer, __cv_wakeup, (unsigned long)current);
timer.expires = expire_time;
add_timer(&timer);
io_schedule();
del_timer_sync(&timer);
time_left = expire_time - jiffies;
return (time_left < 0 ? 0 : time_left);
}
#endif
/* /*
* 'expire_time' argument is an absolute wall clock time in jiffies. * 'expire_time' argument is an absolute wall clock time in jiffies.
@ -156,7 +185,7 @@ EXPORT_SYMBOL(__cv_wait_io);
*/ */
static clock_t static clock_t
__cv_timedwait_common(kcondvar_t *cvp, kmutex_t *mp, clock_t expire_time, __cv_timedwait_common(kcondvar_t *cvp, kmutex_t *mp, clock_t expire_time,
int state) int state, int io)
{ {
DEFINE_WAIT(wait); DEFINE_WAIT(wait);
kmutex_t *m; kmutex_t *m;
@ -188,6 +217,9 @@ __cv_timedwait_common(kcondvar_t *cvp, kmutex_t *mp, clock_t expire_time,
* race where 'cvp->cv_waiters > 0' but the list is empty. * race where 'cvp->cv_waiters > 0' but the list is empty.
*/ */
mutex_exit(mp); mutex_exit(mp);
if (io)
time_left = spl_io_schedule_timeout(time_left);
else
time_left = schedule_timeout(time_left); time_left = schedule_timeout(time_left);
/* No more waiters a different mutex could be used */ /* No more waiters a different mutex could be used */
@ -214,14 +246,24 @@ __cv_timedwait_common(kcondvar_t *cvp, kmutex_t *mp, clock_t expire_time,
clock_t clock_t
__cv_timedwait(kcondvar_t *cvp, kmutex_t *mp, clock_t exp_time) __cv_timedwait(kcondvar_t *cvp, kmutex_t *mp, clock_t exp_time)
{ {
return (__cv_timedwait_common(cvp, mp, exp_time, TASK_UNINTERRUPTIBLE)); return (__cv_timedwait_common(cvp, mp, exp_time,
TASK_UNINTERRUPTIBLE, 0));
} }
EXPORT_SYMBOL(__cv_timedwait); EXPORT_SYMBOL(__cv_timedwait);
clock_t
__cv_timedwait_io(kcondvar_t *cvp, kmutex_t *mp, clock_t exp_time)
{
return (__cv_timedwait_common(cvp, mp, exp_time,
TASK_UNINTERRUPTIBLE, 1));
}
EXPORT_SYMBOL(__cv_timedwait_io);
clock_t clock_t
__cv_timedwait_sig(kcondvar_t *cvp, kmutex_t *mp, clock_t exp_time) __cv_timedwait_sig(kcondvar_t *cvp, kmutex_t *mp, clock_t exp_time)
{ {
return (__cv_timedwait_common(cvp, mp, exp_time, TASK_INTERRUPTIBLE)); return (__cv_timedwait_common(cvp, mp, exp_time,
TASK_INTERRUPTIBLE, 0));
} }
EXPORT_SYMBOL(__cv_timedwait_sig); EXPORT_SYMBOL(__cv_timedwait_sig);