diff options
author | Brian Behlendorf <[email protected]> | 2018-01-24 11:33:47 -0800 |
---|---|---|
committer | GitHub <[email protected]> | 2018-01-24 11:33:47 -0800 |
commit | 23602fdb39e1254c669707ec9d2d0e6bcdbf1771 (patch) | |
tree | c294d9b4733ee141b6457285c6184e74fa0143a5 | |
parent | fb79036f288ea60b59d21fe250bc17445cf69f37 (diff) |
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 <[email protected]>
Signed-off-by: Brian Behlendorf <[email protected]>
Closes #674
-rw-r--r-- | config/spl-build.m4 | 21 | ||||
-rw-r--r-- | include/sys/condvar.h | 2 | ||||
-rw-r--r-- | module/spl/spl-condvar.c | 58 |
3 files changed, 73 insertions, 8 deletions
diff --git a/config/spl-build.m4 b/config/spl-build.m4 index 926abd5c8..afc8de65f 100644 --- a/config/spl-build.m4 +++ b/config/spl-build.m4 @@ -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 @@ -1599,6 +1600,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 dnl # the offset as a pointer which is needed by vn_rdwr(). diff --git a/include/sys/condvar.h b/include/sys/condvar.h index 5479e75ad..5fcc9068a 100644 --- a/include/sys/condvar.h +++ b/include/sys/condvar.h @@ -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); @@ -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) diff --git a/module/spl/spl-condvar.c b/module/spl/spl-condvar.c index 80c2ef090..4778fb256 100644 --- a/module/spl/spl-condvar.c +++ b/module/spl/spl-condvar.c @@ -137,18 +137,47 @@ __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. @@ -156,7 +185,7 @@ EXPORT_SYMBOL(__cv_wait_io); */ 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; @@ -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)) { @@ -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); |