From 8c2e83bab199f5d8820e27c77c7a97cee9cdd965 Mon Sep 17 00:00:00 2001 From: Simon Wilkinson Date: Tue, 19 Apr 2011 08:18:56 +0100 Subject: [PATCH] Linux CM: Update wait code 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 Reviewed-by: Derrick Brashear --- src/afs/LINUX/osi_compat.h | 61 +++++++++++++++++++++++++++++++++++--- src/afs/LINUX/osi_sleep.c | 60 +++++++++++-------------------------- 2 files changed, 74 insertions(+), 47 deletions(-) diff --git a/src/afs/LINUX/osi_compat.h b/src/afs/LINUX/osi_compat.h index b94295c06..62137341a 100644 --- a/src/afs/LINUX/osi_compat.h +++ b/src/afs/LINUX/osi_compat.h @@ -279,21 +279,39 @@ 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 */ diff --git a/src/afs/LINUX/osi_sleep.c b/src/afs/LINUX/osi_sleep.c index 31b514985..d9e2967d0 100644 --- a/src/afs/LINUX/osi_sleep.c +++ b/src/afs/LINUX/osi_sleep.c @@ -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); -- 2.39.5