summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Behlendorf <[email protected]>2018-01-24 11:33:47 -0800
committerGitHub <[email protected]>2018-01-24 11:33:47 -0800
commit23602fdb39e1254c669707ec9d2d0e6bcdbf1771 (patch)
treec294d9b4733ee141b6457285c6184e74fa0143a5
parentfb79036f288ea60b59d21fe250bc17445cf69f37 (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.m421
-rw-r--r--include/sys/condvar.h2
-rw-r--r--module/spl/spl-condvar.c58
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);