Skip to content

Commit

Permalink
Merge branch 'freezer'
Browse files Browse the repository at this point in the history
* freezer:
  af_unix: use freezable blocking calls in read
  sigtimedwait: use freezable blocking call
  nanosleep: use freezable blocking call
  futex: use freezable blocking call
  select: use freezable blocking call
  epoll: use freezable blocking call
  binder: use freezable blocking calls
  freezer: add new freezable helpers using freezer_do_not_count()
  freezer: convert freezable helpers to static inline where possible
  freezer: convert freezable helpers to freezer_do_not_count()
  freezer: skip waking up tasks with PF_FREEZER_SKIP set
  freezer: shorten freezer sleep time using exponential backoff
  lockdep: check that no locks held at freeze time
  lockdep: remove task argument from debug_check_no_locks_held
  freezer: add unsafe versions of freezable helpers for CIFS
  freezer: add unsafe versions of freezable helpers for NFS
  • Loading branch information
rafaeljw committed Jun 28, 2013
2 parents e8b6cb3 + 2b15af6 commit 207bc11
Show file tree
Hide file tree
Showing 18 changed files with 200 additions and 68 deletions.
5 changes: 3 additions & 2 deletions drivers/staging/android/binder.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <asm/cacheflush.h>
#include <linux/fdtable.h>
#include <linux/file.h>
#include <linux/freezer.h>
#include <linux/fs.h>
#include <linux/list.h>
#include <linux/miscdevice.h>
Expand Down Expand Up @@ -2140,13 +2141,13 @@ static int binder_thread_read(struct binder_proc *proc,
if (!binder_has_proc_work(proc, thread))
ret = -EAGAIN;
} else
ret = wait_event_interruptible_exclusive(proc->wait, binder_has_proc_work(proc, thread));
ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread));
} else {
if (non_block) {
if (!binder_has_thread_work(thread))
ret = -EAGAIN;
} else
ret = wait_event_interruptible(thread->wait, binder_has_thread_work(thread));
ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread));
}

binder_lock(__func__);
Expand Down
2 changes: 1 addition & 1 deletion fs/cifs/transport.c
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,7 @@ wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ)
{
int error;

error = wait_event_freezekillable(server->response_q,
error = wait_event_freezekillable_unsafe(server->response_q,
midQ->mid_state != MID_REQUEST_SUBMITTED);
if (error < 0)
return -ERESTARTSYS;
Expand Down
4 changes: 3 additions & 1 deletion fs/eventpoll.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include <linux/mutex.h>
#include <linux/anon_inodes.h>
#include <linux/device.h>
#include <linux/freezer.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/mman.h>
Expand Down Expand Up @@ -1602,7 +1603,8 @@ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
}

spin_unlock_irqrestore(&ep->lock, flags);
if (!schedule_hrtimeout_range(to, slack, HRTIMER_MODE_ABS))
if (!freezable_schedule_hrtimeout_range(to, slack,
HRTIMER_MODE_ABS))
timed_out = 1;

spin_lock_irqsave(&ep->lock, flags);
Expand Down
2 changes: 1 addition & 1 deletion fs/nfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ int nfs_wait_bit_killable(void *word)
{
if (fatal_signal_pending(current))
return -ERESTARTSYS;
freezable_schedule();
freezable_schedule_unsafe();
return 0;
}
EXPORT_SYMBOL_GPL(nfs_wait_bit_killable);
Expand Down
2 changes: 1 addition & 1 deletion fs/nfs/nfs3proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
res = rpc_call_sync(clnt, msg, flags);
if (res != -EJUKEBOX)
break;
freezable_schedule_timeout_killable(NFS_JUKEBOX_RETRY_TIME);
freezable_schedule_timeout_killable_unsafe(NFS_JUKEBOX_RETRY_TIME);
res = -ERESTARTSYS;
} while (!fatal_signal_pending(current));
return res;
Expand Down
4 changes: 2 additions & 2 deletions fs/nfs/nfs4proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ static int nfs4_delay(struct rpc_clnt *clnt, long *timeout)
*timeout = NFS4_POLL_RETRY_MIN;
if (*timeout > NFS4_POLL_RETRY_MAX)
*timeout = NFS4_POLL_RETRY_MAX;
freezable_schedule_timeout_killable(*timeout);
freezable_schedule_timeout_killable_unsafe(*timeout);
if (fatal_signal_pending(current))
res = -ERESTARTSYS;
*timeout <<= 1;
Expand Down Expand Up @@ -4528,7 +4528,7 @@ int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4
static unsigned long
nfs4_set_lock_task_retry(unsigned long timeout)
{
freezable_schedule_timeout_killable(timeout);
freezable_schedule_timeout_killable_unsafe(timeout);
timeout <<= 1;
if (timeout > NFS4_LOCK_MAXTIMEOUT)
return NFS4_LOCK_MAXTIMEOUT;
Expand Down
4 changes: 3 additions & 1 deletion fs/select.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <linux/rcupdate.h>
#include <linux/hrtimer.h>
#include <linux/sched/rt.h>
#include <linux/freezer.h>

#include <asm/uaccess.h>

Expand Down Expand Up @@ -236,7 +237,8 @@ int poll_schedule_timeout(struct poll_wqueues *pwq, int state,

set_current_state(state);
if (!pwq->triggered)
rc = schedule_hrtimeout_range(expires, slack, HRTIMER_MODE_ABS);
rc = freezable_schedule_hrtimeout_range(expires, slack,
HRTIMER_MODE_ABS);
__set_current_state(TASK_RUNNING);

/*
Expand Down
4 changes: 2 additions & 2 deletions include/linux/debug_locks.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ struct task_struct;
extern void debug_show_all_locks(void);
extern void debug_show_held_locks(struct task_struct *task);
extern void debug_check_no_locks_freed(const void *from, unsigned long len);
extern void debug_check_no_locks_held(struct task_struct *task);
extern void debug_check_no_locks_held(void);
#else
static inline void debug_show_all_locks(void)
{
Expand All @@ -67,7 +67,7 @@ debug_check_no_locks_freed(const void *from, unsigned long len)
}

static inline void
debug_check_no_locks_held(struct task_struct *task)
debug_check_no_locks_held(void)
{
}
#endif
Expand Down
171 changes: 140 additions & 31 deletions include/linux/freezer.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#ifndef FREEZER_H_INCLUDED
#define FREEZER_H_INCLUDED

#include <linux/debug_locks.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/atomic.h>
Expand Down Expand Up @@ -46,14 +47,25 @@ extern int freeze_kernel_threads(void);
extern void thaw_processes(void);
extern void thaw_kernel_threads(void);

static inline bool try_to_freeze(void)
/*
* DO NOT ADD ANY NEW CALLERS OF THIS FUNCTION
* If try_to_freeze causes a lockdep warning it means the caller may deadlock
*/
static inline bool try_to_freeze_unsafe(void)
{
might_sleep();
if (likely(!freezing(current)))
return false;
return __refrigerator(false);
}

static inline bool try_to_freeze(void)
{
if (!(current->flags & PF_NOFREEZE))
debug_check_no_locks_held();
return try_to_freeze_unsafe();
}

extern bool freeze_task(struct task_struct *p);
extern bool set_freezable(void);

Expand Down Expand Up @@ -115,6 +127,14 @@ static inline void freezer_count(void)
try_to_freeze();
}

/* DO NOT ADD ANY NEW CALLERS OF THIS FUNCTION */
static inline void freezer_count_unsafe(void)
{
current->flags &= ~PF_FREEZER_SKIP;
smp_mb();
try_to_freeze_unsafe();
}

/**
* freezer_should_skip - whether to skip a task when determining frozen
* state is reached
Expand All @@ -139,28 +159,86 @@ static inline bool freezer_should_skip(struct task_struct *p)
}

/*
* These macros are intended to be used whenever you want allow a sleeping
* These functions are intended to be used whenever you want allow a sleeping
* task to be frozen. Note that neither return any clear indication of
* whether a freeze event happened while in this function.
*/

/* Like schedule(), but should not block the freezer. */
#define freezable_schedule() \
({ \
freezer_do_not_count(); \
schedule(); \
freezer_count(); \
})
static inline void freezable_schedule(void)
{
freezer_do_not_count();
schedule();
freezer_count();
}

/* DO NOT ADD ANY NEW CALLERS OF THIS FUNCTION */
static inline void freezable_schedule_unsafe(void)
{
freezer_do_not_count();
schedule();
freezer_count_unsafe();
}

/*
* Like freezable_schedule_timeout(), but should not block the freezer. Do not
* call this with locks held.
*/
static inline long freezable_schedule_timeout(long timeout)
{
long __retval;
freezer_do_not_count();
__retval = schedule_timeout(timeout);
freezer_count();
return __retval;
}

/*
* Like schedule_timeout_interruptible(), but should not block the freezer. Do not
* call this with locks held.
*/
static inline long freezable_schedule_timeout_interruptible(long timeout)
{
long __retval;
freezer_do_not_count();
__retval = schedule_timeout_interruptible(timeout);
freezer_count();
return __retval;
}

/* Like schedule_timeout_killable(), but should not block the freezer. */
#define freezable_schedule_timeout_killable(timeout) \
({ \
long __retval; \
freezer_do_not_count(); \
__retval = schedule_timeout_killable(timeout); \
freezer_count(); \
__retval; \
})
static inline long freezable_schedule_timeout_killable(long timeout)
{
long __retval;
freezer_do_not_count();
__retval = schedule_timeout_killable(timeout);
freezer_count();
return __retval;
}

/* DO NOT ADD ANY NEW CALLERS OF THIS FUNCTION */
static inline long freezable_schedule_timeout_killable_unsafe(long timeout)
{
long __retval;
freezer_do_not_count();
__retval = schedule_timeout_killable(timeout);
freezer_count_unsafe();
return __retval;
}

/*
* Like schedule_hrtimeout_range(), but should not block the freezer. Do not
* call this with locks held.
*/
static inline int freezable_schedule_hrtimeout_range(ktime_t *expires,
unsigned long delta, const enum hrtimer_mode mode)
{
int __retval;
freezer_do_not_count();
__retval = schedule_hrtimeout_range(expires, delta, mode);
freezer_count();
return __retval;
}

/*
* Freezer-friendly wrappers around wait_event_interruptible(),
Expand All @@ -177,33 +255,45 @@ static inline bool freezer_should_skip(struct task_struct *p)
__retval; \
})

/* DO NOT ADD ANY NEW CALLERS OF THIS FUNCTION */
#define wait_event_freezekillable_unsafe(wq, condition) \
({ \
int __retval; \
freezer_do_not_count(); \
__retval = wait_event_killable(wq, (condition)); \
freezer_count_unsafe(); \
__retval; \
})

#define wait_event_freezable(wq, condition) \
({ \
int __retval; \
for (;;) { \
__retval = wait_event_interruptible(wq, \
(condition) || freezing(current)); \
if (__retval || (condition)) \
break; \
try_to_freeze(); \
} \
freezer_do_not_count(); \
__retval = wait_event_interruptible(wq, (condition)); \
freezer_count(); \
__retval; \
})

#define wait_event_freezable_timeout(wq, condition, timeout) \
({ \
long __retval = timeout; \
for (;;) { \
__retval = wait_event_interruptible_timeout(wq, \
(condition) || freezing(current), \
__retval); \
if (__retval <= 0 || (condition)) \
break; \
try_to_freeze(); \
} \
freezer_do_not_count(); \
__retval = wait_event_interruptible_timeout(wq, (condition), \
__retval); \
freezer_count(); \
__retval; \
})

#define wait_event_freezable_exclusive(wq, condition) \
({ \
int __retval; \
freezer_do_not_count(); \
__retval = wait_event_interruptible_exclusive(wq, condition); \
freezer_count(); \
__retval; \
})


#else /* !CONFIG_FREEZER */
static inline bool frozen(struct task_struct *p) { return false; }
static inline bool freezing(struct task_struct *p) { return false; }
Expand All @@ -225,18 +315,37 @@ static inline void set_freezable(void) {}

#define freezable_schedule() schedule()

#define freezable_schedule_unsafe() schedule()

#define freezable_schedule_timeout(timeout) schedule_timeout(timeout)

#define freezable_schedule_timeout_interruptible(timeout) \
schedule_timeout_interruptible(timeout)

#define freezable_schedule_timeout_killable(timeout) \
schedule_timeout_killable(timeout)

#define freezable_schedule_timeout_killable_unsafe(timeout) \
schedule_timeout_killable(timeout)

#define freezable_schedule_hrtimeout_range(expires, delta, mode) \
schedule_hrtimeout_range(expires, delta, mode)

#define wait_event_freezable(wq, condition) \
wait_event_interruptible(wq, condition)

#define wait_event_freezable_timeout(wq, condition, timeout) \
wait_event_interruptible_timeout(wq, condition, timeout)

#define wait_event_freezable_exclusive(wq, condition) \
wait_event_interruptible_exclusive(wq, condition)

#define wait_event_freezekillable(wq, condition) \
wait_event_killable(wq, condition)

#define wait_event_freezekillable_unsafe(wq, condition) \
wait_event_killable(wq, condition)

#endif /* !CONFIG_FREEZER */

#endif /* FREEZER_H_INCLUDED */
2 changes: 1 addition & 1 deletion kernel/exit.c
Original file line number Diff line number Diff line change
Expand Up @@ -835,7 +835,7 @@ void do_exit(long code)
/*
* Make sure we are holding no locks:
*/
debug_check_no_locks_held(tsk);
debug_check_no_locks_held();
/*
* We can do this unlocked here. The futex code uses this flag
* just to verify whether the pi state cleanup has been done
Expand Down
Loading

0 comments on commit 207bc11

Please sign in to comment.