504b3ab
@@ -, +, @@ 
504b3ab
 fs/nfs/inode.c          |    3 ++-
504b3ab
 fs/nfs/nfs3proc.c       |    3 ++-
504b3ab
 fs/nfs/nfs4proc.c       |    5 +++--
504b3ab
 fs/nfs/proc.c           |    3 ++-
504b3ab
 include/linux/freezer.h |   28 ++++++++++++++++++++++++++++
504b3ab
 net/sunrpc/sched.c      |    3 ++-
504b3ab
 6 files changed, 39 insertions(+), 6 deletions(-)
504b3ab
--- a/fs/nfs/inode.c	
504b3ab
+++ a/fs/nfs/inode.c	
504b3ab
@@ -38,6 +38,7 @@ 
504b3ab
 #include <linux/nfs_xdr.h>
504b3ab
 #include <linux/slab.h>
504b3ab
 #include <linux/compat.h>
504b3ab
+#include <linux/freezer.h>
504b3ab
 
504b3ab
 #include <asm/system.h>
504b3ab
 #include <asm/uaccess.h>
504b3ab
@@ -77,7 +78,7 @@ int nfs_wait_bit_killable(void *word)
504b3ab
 {
504b3ab
 	if (fatal_signal_pending(current))
504b3ab
 		return -ERESTARTSYS;
504b3ab
-	schedule();
504b3ab
+	freezable_schedule();
504b3ab
 	return 0;
504b3ab
 }
504b3ab
 
504b3ab
--- a/fs/nfs/nfs3proc.c	
504b3ab
+++ a/fs/nfs/nfs3proc.c	
504b3ab
@@ -17,6 +17,7 @@ 
504b3ab
 #include <linux/nfs_page.h>
504b3ab
 #include <linux/lockd/bind.h>
504b3ab
 #include <linux/nfs_mount.h>
504b3ab
+#include <linux/freezer.h>
504b3ab
 
504b3ab
 #include "iostat.h"
504b3ab
 #include "internal.h"
504b3ab
@@ -32,7 +33,7 @@ nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
504b3ab
 		res = rpc_call_sync(clnt, msg, flags);
504b3ab
 		if (res != -EJUKEBOX && res != -EKEYEXPIRED)
504b3ab
 			break;
504b3ab
-		schedule_timeout_killable(NFS_JUKEBOX_RETRY_TIME);
504b3ab
+		freezable_schedule_timeout_killable(NFS_JUKEBOX_RETRY_TIME);
504b3ab
 		res = -ERESTARTSYS;
504b3ab
 	} while (!fatal_signal_pending(current));
504b3ab
 	return res;
504b3ab
--- a/fs/nfs/nfs4proc.c	
504b3ab
+++ a/fs/nfs/nfs4proc.c	
504b3ab
@@ -53,6 +53,7 @@ 
504b3ab
 #include <linux/sunrpc/bc_xprt.h>
504b3ab
 #include <linux/xattr.h>
504b3ab
 #include <linux/utsname.h>
504b3ab
+#include <linux/freezer.h>
504b3ab
 
504b3ab
 #include "nfs4_fs.h"
504b3ab
 #include "delegation.h"
Dave Jones 8c3a2d0
@@ -241,7 +242,7 @@ static int nfs4_delay(struct rpc_clnt *clnt, long *timeout)
504b3ab
 		*timeout = NFS4_POLL_RETRY_MIN;
504b3ab
 	if (*timeout > NFS4_POLL_RETRY_MAX)
504b3ab
 		*timeout = NFS4_POLL_RETRY_MAX;
504b3ab
-	schedule_timeout_killable(*timeout);
504b3ab
+	freezable_schedule_timeout_killable(*timeout);
504b3ab
 	if (fatal_signal_pending(current))
504b3ab
 		res = -ERESTARTSYS;
504b3ab
 	*timeout <<= 1;
Dave Jones 8c3a2d0
@@ -3950,7 +3951,7 @@ int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4
504b3ab
 static unsigned long
504b3ab
 nfs4_set_lock_task_retry(unsigned long timeout)
504b3ab
 {
504b3ab
-	schedule_timeout_killable(timeout);
504b3ab
+	freezable_schedule_timeout_killable(timeout);
504b3ab
 	timeout <<= 1;
504b3ab
 	if (timeout > NFS4_LOCK_MAXTIMEOUT)
504b3ab
 		return NFS4_LOCK_MAXTIMEOUT;
504b3ab
--- a/fs/nfs/proc.c	
504b3ab
+++ a/fs/nfs/proc.c	
504b3ab
@@ -41,6 +41,7 @@ 
504b3ab
 #include <linux/nfs_fs.h>
504b3ab
 #include <linux/nfs_page.h>
504b3ab
 #include <linux/lockd/bind.h>
504b3ab
+#include <linux/freezer.h>
504b3ab
 #include "internal.h"
504b3ab
 
504b3ab
 #define NFSDBG_FACILITY		NFSDBG_PROC
504b3ab
@@ -59,7 +60,7 @@ nfs_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
504b3ab
 		res = rpc_call_sync(clnt, msg, flags);
504b3ab
 		if (res != -EKEYEXPIRED)
504b3ab
 			break;
504b3ab
-		schedule_timeout_killable(NFS_JUKEBOX_RETRY_TIME);
504b3ab
+		freezable_schedule_timeout_killable(NFS_JUKEBOX_RETRY_TIME);
504b3ab
 		res = -ERESTARTSYS;
504b3ab
 	} while (!fatal_signal_pending(current));
504b3ab
 	return res;
504b3ab
--- a/include/linux/freezer.h	
504b3ab
+++ a/include/linux/freezer.h	
Dave Jones 8c3a2d0
@@ -135,6 +135,29 @@ static inline void set_freezable_with_signal(void)
504b3ab
 }
504b3ab
 
504b3ab
 /*
504b3ab
+ * These macros are intended to be used whenever you want allow a task that's
504b3ab
+ * sleeping in TASK_UNINTERRUPTIBLE or TASK_KILLABLE state to be frozen. Note
504b3ab
+ * that neither return any clear indication of whether a freeze event happened
504b3ab
+ * while in this function.
504b3ab
+ */
504b3ab
+
504b3ab
+/* Like schedule(), but should not block the freezer. */
504b3ab
+#define freezable_schedule()						\
504b3ab
+({									\
504b3ab
+	freezer_do_not_count();						\
504b3ab
+	schedule();							\
504b3ab
+	freezer_count();						\
504b3ab
+})
504b3ab
+
504b3ab
+/* Like schedule_timeout_killable(), but should not block the freezer. */
504b3ab
+#define freezable_schedule_timeout_killable(timeout)			\
504b3ab
+({									\
504b3ab
+	freezer_do_not_count();						\
504b3ab
+	schedule_timeout_killable(timeout);				\
504b3ab
+	freezer_count();						\
504b3ab
+})
504b3ab
+
504b3ab
+/*
504b3ab
  * Freezer-friendly wrappers around wait_event_interruptible(),
504b3ab
  * wait_event_killable() and wait_event_interruptible_timeout(), originally
504b3ab
  * defined in <linux/wait.h>
Dave Jones 8c3a2d0
@@ -194,6 +217,11 @@ static inline int freezer_should_skip(struct task_struct *p) { return 0; }
504b3ab
 static inline void set_freezable(void) {}
504b3ab
 static inline void set_freezable_with_signal(void) {}
504b3ab
 
504b3ab
+#define freezable_schedule()  schedule()
504b3ab
+
504b3ab
+#define freezable_schedule_timeout_killable(timeout)			\
504b3ab
+	schedule_timeout_killable(timeout)
504b3ab
+
504b3ab
 #define wait_event_freezable(wq, condition)				\
504b3ab
 		wait_event_interruptible(wq, condition)
504b3ab
 
504b3ab
--- a/net/sunrpc/sched.c	
504b3ab
+++ a/net/sunrpc/sched.c	
504b3ab
@@ -18,6 +18,7 @@ 
504b3ab
 #include <linux/smp.h>
504b3ab
 #include <linux/spinlock.h>
504b3ab
 #include <linux/mutex.h>
504b3ab
+#include <linux/freezer.h>
504b3ab
 
504b3ab
 #include <linux/sunrpc/clnt.h>
504b3ab
 
504b3ab
@@ -231,7 +232,7 @@ static int rpc_wait_bit_killable(void *word)
504b3ab
 {
504b3ab
 	if (fatal_signal_pending(current))
504b3ab
 		return -ERESTARTSYS;
504b3ab
-	schedule();
504b3ab
+	freezable_schedule();
504b3ab
 	return 0;
504b3ab
 }
504b3ab
 
504b3ab
 include/linux/freezer.h |   21 ++++++++++++++++++---
504b3ab
 1 files changed, 18 insertions(+), 3 deletions(-)
504b3ab
--- a/include/linux/freezer.h	
504b3ab
+++ a/include/linux/freezer.h	
Dave Jones 8c3a2d0
@@ -141,18 +141,33 @@ static inline void set_freezable_with_signal(void)
504b3ab
  * while in this function.
504b3ab
  */
504b3ab
 
504b3ab
-/* Like schedule(), but should not block the freezer. */
504b3ab
+/*
504b3ab
+ * Like schedule(), but should not block the freezer. It may return immediately
504b3ab
+ * if it ends up racing with the freezer. Callers must be able to deal with
504b3ab
+ * spurious wakeups.
504b3ab
+ */
504b3ab
 #define freezable_schedule()						\
504b3ab
 ({									\
504b3ab
 	freezer_do_not_count();						\
504b3ab
-	schedule();							\
504b3ab
+	if (!try_to_freeze())						\
504b3ab
+		schedule();						\
504b3ab
 	freezer_count();						\
504b3ab
 })
504b3ab
 
504b3ab
-/* Like schedule_timeout_killable(), but should not block the freezer. */
504b3ab
+/*
504b3ab
+ * Like schedule_timeout_killable(), but should not block the freezer. It may
504b3ab
+ * end up returning immediately if it ends up racing with the freezer. Callers
504b3ab
+ * must be able to deal with the loose wakeup timing that can occur when the
504b3ab
+ * freezer races in. When that occurs, this function will return the timeout
504b3ab
+ * value instead of 0.
504b3ab
+ */
504b3ab
 #define freezable_schedule_timeout_killable(timeout)			\
504b3ab
 ({									\
504b3ab
 	freezer_do_not_count();						\
504b3ab
+	if (try_to_freeze()) {						\
504b3ab
+		freezer_count();					\
504b3ab
+		return timeout;						\
504b3ab
+	}								\
504b3ab
 	schedule_timeout_killable(timeout);				\
504b3ab
 	freezer_count();						\
504b3ab
 })