Linux CM: Update wait code
authorSimon Wilkinson <sxw@your-file-system.com>
Tue, 19 Apr 2011 07:18:56 +0000 (08:18 +0100)
committerDerrick Brashear <shadow@dementia.org>
Sun, 5 Jun 2011 15:10:41 +0000 (08:10 -0700)
Update the wait code to use the more modern wait_event_freezable()
macros. If those macros are not available, fall back to the older
wait_event_interruptible macro, and build our own
wait_event_freezable on top of this.

These changes should simplify our interactions with the wait queue
and refrigerator bits of the kernel, as we're now using more standard
interfaces to them.

Change-Id: I5218c8a1b5b33f10355ef298008c53e416b267f9
Reviewed-on: http://gerrit.openafs.org/4753
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Derrick Brashear <shadow@dementia.org>

src/afs/LINUX/osi_compat.h
src/afs/LINUX/osi_sleep.c

index b94295c..6213734 100644 (file)
@@ -279,22 +279,40 @@ kernel_getsockopt(struct socket *sockp, int level, int name, char *val,
 #endif
 
 #ifdef HAVE_TRY_TO_FREEZE
-static inline void
+static inline int
 afs_try_to_freeze(void) {
 # ifdef LINUX_REFRIGERATOR_TAKES_PF_FREEZE
-    try_to_freeze(PF_FREEZE);
+    return try_to_freeze(PF_FREEZE);
 # else
-    try_to_freeze();
+    return try_to_freeze();
 # endif
 }
 #else
-static inline void
+static inline int
 afs_try_to_freeze(void) {
 # ifdef CONFIG_PM
     if (current->flags & PF_FREEZE) {
        refrigerator(PF_FREEZE);
+       return 1;
     }
 # endif
+    return 0;
+}
+#endif
+
+/* The commit which changed refrigerator so that it takes no arguments
+ * also added freezing(), so if LINUX_REFRIGERATOR_TAKES_PF_FREEZE is
+ * true, the kernel doesn't have a freezing() function.
+ */
+#ifdef LINUX_REFRIGERATOR_TAKES_PF_FREEZE
+static inline int
+freezing(struct task_struct *p)
+{
+# ifdef CONFIG_PM
+    return p->flags & PF_FREEZE;
+# else
+    return 0;
+# endif
 }
 #endif
 
@@ -441,4 +459,39 @@ afs_get_dentry_ref(struct path *path, struct vfsmount **mnt, struct dentry **dpp
 #endif
 }
 
+/* wait_event_freezable appeared with 2.6.24 */
+
+/* These implement the original AFS wait behaviour, with respect to the
+ * refrigerator, rather than the behaviour of the current wait_event_freezable
+ * implementation.
+ */
+
+#ifndef wait_event_freezable
+# define wait_event_freezable(waitqueue, condition)                            \
+({                                                                             \
+    int _ret;                                                                  \
+    do {                                                                       \
+       _ret = wait_event_interruptible(waitqueue,                              \
+                                       (condition) || freezing(current));      \
+       if (_ret && !freezing(current))                                 \
+           break;                                                              \
+       else if (!(condition))                                                  \
+           _ret = -EINTR;                                                      \
+    } while (afs_try_to_freeze());                                             \
+    _ret;                                                                      \
+})
+
+# define wait_event_freezable_timeout(waitqueue, condition, timeout)           \
+({                                                                             \
+     int _ret;                                                                 \
+     do {                                                                      \
+       _ret = wait_event_interruptible_timeout(waitqueue,                      \
+                                               (condition ||                   \
+                                                freezing(current)),            \
+                                               timeout);                       \
+     } while (afs_try_to_freeze());                                            \
+     _ret;                                                                     \
+})
+#endif
+
 #endif /* AFS_LINUX_OSI_COMPAT_H */
index 31b5149..d9e2967 100644 (file)
@@ -67,9 +67,6 @@ afs_osi_Wait(afs_int32 ams, struct afs_osi_WaitHandle *ahandle, int aintok)
     return code;
 }
 
-
-
-
 typedef struct afs_event {
     struct afs_event *next;    /* next in hash chain */
     char *event;               /* lwp event: an address */
@@ -169,11 +166,7 @@ afs_osi_SleepSig(void *event)
 {
     struct afs_event *evp;
     int seq, retval;
-#ifdef DECLARE_WAITQUEUE
-    DECLARE_WAITQUEUE(wait, current);
-#else
-    struct wait_queue wait = { current, NULL };
-#endif
+    int code;
 
     evp = afs_getevent(event);
     if (!evp) {
@@ -184,25 +177,17 @@ afs_osi_SleepSig(void *event)
     seq = evp->seq;
     retval = 0;
 
-    add_wait_queue(&evp->cond, &wait);
-    while (seq == evp->seq) {
-       set_current_state(TASK_INTERRUPTIBLE);
-       AFS_ASSERT_GLOCK();
-       AFS_GUNLOCK();
-       schedule();
-       afs_try_to_freeze();
+    AFS_GUNLOCK();
+    code = wait_event_freezable(evp->cond, seq != evp->seq);
+    AFS_GLOCK();
 
-       AFS_GLOCK();
-       if (signal_pending(current)) {
-           retval = EINTR;
-           break;
-       }
-    }
-    remove_wait_queue(&evp->cond, &wait);
-    set_current_state(TASK_RUNNING);
+    if (code == -ERESTARTSYS)
+       code = EINTR;
+    else
+       code = -code;
 
     relevent(evp);
-    return retval;
+    return code;
 }
 
 /* afs_osi_Sleep -- waits for an event to be notified, ignoring signals.
@@ -247,11 +232,7 @@ afs_osi_TimedSleep(void *event, afs_int32 ams, int aintok)
     int code = 0;
     long ticks = (ams * HZ / 1000) + 1;
     struct afs_event *evp;
-#ifdef DECLARE_WAITQUEUE
-    DECLARE_WAITQUEUE(wait, current);
-#else
-    struct wait_queue wait = { current, NULL };
-#endif
+    int seq;
 
     evp = afs_getevent(event);
     if (!evp) {
@@ -259,22 +240,15 @@ afs_osi_TimedSleep(void *event, afs_int32 ams, int aintok)
        evp = afs_getevent(event);
     }
 
-    add_wait_queue(&evp->cond, &wait);
-    set_current_state(TASK_INTERRUPTIBLE);
-    /* always sleep TASK_INTERRUPTIBLE to keep load average
-     * from artifically increasing. */
-    AFS_GUNLOCK();
-
-    if (schedule_timeout(ticks)) {
-       if (aintok)
-           code = EINTR;
-    }
-
-    afs_try_to_freeze();
+    seq = evp->seq;
 
+    AFS_GUNLOCK();
+    code = wait_event_freezable_timeout(evp->cond, evp->seq != seq, ticks);
     AFS_GLOCK();
-    remove_wait_queue(&evp->cond, &wait);
-    set_current_state(TASK_RUNNING);
+    if (code == -ERESTARTSYS)
+       code = EINTR;
+    else
+       code = -code;
 
     relevent(evp);