#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
#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 */
return code;
}
-
-
-
typedef struct afs_event {
struct afs_event *next; /* next in hash chain */
char *event; /* lwp event: an address */
{
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) {
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.
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) {
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);