Skip to content
This repository has been archived by the owner on Feb 26, 2020. It is now read-only.

Commit

Permalink
Add cv_timedwait_io()
Browse files Browse the repository at this point in the history
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
  • Loading branch information
behlendorf authored Jan 24, 2018
1 parent fb79036 commit 23602fd
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 8 deletions.
21 changes: 21 additions & 0 deletions config/spl-build.m4
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ AC_DEFUN([SPL_AC_CONFIG_KERNEL], [
SPL_AC_KMEM_CACHE_CREATE_USERCOPY
SPL_AC_WAIT_QUEUE_ENTRY_T
SPL_AC_WAIT_QUEUE_HEAD_ENTRY
SPL_AC_IO_SCHEDULE_TIMEOUT
SPL_AC_KERNEL_WRITE
SPL_AC_KERNEL_READ
SPL_AC_KERNEL_TIMER_FUNCTION_TIMER_LIST
Expand Down Expand Up @@ -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 # 4.14 API change
dnl # kernel_write() which was introduced in 3.9 was updated to take
Expand Down
2 changes: 2 additions & 0 deletions include/sys/condvar.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_sig(kcondvar_t *, kmutex_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_hires(kcondvar_t *, kmutex_t *, hrtime_t,
hrtime_t res, int flag);
Expand All @@ -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_interruptible(cvp, mp) cv_wait_sig(cvp, mp)
#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_interruptible(cvp, mp, t) cv_timedwait_sig(cvp, mp, t)
#define cv_signal(cvp) __cv_signal(cvp)
Expand Down
58 changes: 50 additions & 8 deletions module/spl/spl-condvar.c
Original file line number Diff line number Diff line change
Expand Up @@ -136,27 +136,56 @@ __cv_wait(kcondvar_t *cvp, kmutex_t *mp)
}
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
__cv_wait_sig(kcondvar_t *cvp, kmutex_t *mp)
{
cv_wait_common(cvp, mp, TASK_INTERRUPTIBLE, 0);
}
EXPORT_SYMBOL(__cv_wait_sig);

void
__cv_wait_io(kcondvar_t *cvp, kmutex_t *mp)
#if defined(HAVE_IO_SCHEDULE_TIMEOUT)
#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.
* Return value is time left (expire_time - now) or -1 if timeout occurred.
*/
static clock_t
__cv_timedwait_common(kcondvar_t *cvp, kmutex_t *mp, clock_t expire_time,
int state)
int state, int io)
{
DEFINE_WAIT(wait);
kmutex_t *m;
Expand Down Expand Up @@ -188,7 +217,10 @@ __cv_timedwait_common(kcondvar_t *cvp, kmutex_t *mp, clock_t expire_time,
* race where 'cvp->cv_waiters > 0' but the list is empty.
*/
mutex_exit(mp);
time_left = schedule_timeout(time_left);
if (io)
time_left = spl_io_schedule_timeout(time_left);
else
time_left = schedule_timeout(time_left);

/* No more waiters a different mutex could be used */
if (atomic_dec_and_test(&cvp->cv_waiters)) {
Expand All @@ -214,14 +246,24 @@ __cv_timedwait_common(kcondvar_t *cvp, kmutex_t *mp, clock_t expire_time,
clock_t
__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);

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
__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);

Expand Down

0 comments on commit 23602fd

Please sign in to comment.