Skip to content

Commit c122132

Browse files
neilbrownIngo Molnar
authored andcommitted
sched: Allow wait_on_bit_action() functions to support a timeout
It is currently not possible for various wait_on_bit functions to implement a timeout. While the "action" function that is called to do the waiting could certainly use schedule_timeout(), there is no way to carry forward the remaining timeout after a false wake-up. As false-wakeups a clearly possible at least due to possible hash collisions in bit_waitqueue(), this is a real problem. The 'action' function is currently passed a pointer to the word containing the bit being waited on. No current action functions use this pointer. So changing it to something else will be a little noisy but will have no immediate effect. This patch changes the 'action' function to take a pointer to the "struct wait_bit_key", which contains a pointer to the word containing the bit so nothing is really lost. It also adds a 'private' field to "struct wait_bit_key", which is initialized to zero. An action function can now implement a timeout with something like static int timed_out_waiter(struct wait_bit_key *key) { unsigned long waited; if (key->private == 0) { key->private = jiffies; if (key->private == 0) key->private -= 1; } waited = jiffies - key->private; if (waited > 10 * HZ) return -EAGAIN; schedule_timeout(waited - 10 * HZ); return 0; } If any other need for context in a waiter were found it would be easy to use ->private for some other purpose, or even extend "struct wait_bit_key". My particular need is to support timeouts in nfs_release_page() to avoid deadlocks with loopback mounted NFS. While wait_on_bit_timeout() would be a cleaner interface, it will not meet my need. I need the timeout to be sensitive to the state of the connection with the server, which could change. So I need to use an 'action' interface. Signed-off-by: NeilBrown <neilb@suse.de> Acked-by: Peter Zijlstra <peterz@infradead.org> Cc: Oleg Nesterov <oleg@redhat.com> Cc: Steve French <sfrench@samba.org> Cc: David Howells <dhowells@redhat.com> Cc: Steven Whitehouse <swhiteho@redhat.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Link: http://lkml.kernel.org/r/20140707051604.28027.41257.stgit@notabene.brown Signed-off-by: Ingo Molnar <mingo@kernel.org>
1 parent 7431620 commit c122132

File tree

8 files changed

+25
-23
lines changed

8 files changed

+25
-23
lines changed

fs/cifs/inode.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1780,7 +1780,7 @@ cifs_invalidate_mapping(struct inode *inode)
17801780
* @word: long word containing the bit lock
17811781
*/
17821782
static int
1783-
cifs_wait_bit_killable(void *word)
1783+
cifs_wait_bit_killable(struct wait_bit_key *key)
17841784
{
17851785
if (fatal_signal_pending(current))
17861786
return -ERESTARTSYS;

fs/nfs/inode.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ nfs_fattr_to_ino_t(struct nfs_fattr *fattr)
7575
* nfs_wait_bit_killable - helper for functions that are sleeping on bit locks
7676
* @word: long word containing the bit lock
7777
*/
78-
int nfs_wait_bit_killable(void *word)
78+
int nfs_wait_bit_killable(struct wait_bit_key *key)
7979
{
8080
if (fatal_signal_pending(current))
8181
return -ERESTARTSYS;

fs/nfs/internal.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ extern int nfs_drop_inode(struct inode *);
347347
extern void nfs_clear_inode(struct inode *);
348348
extern void nfs_evict_inode(struct inode *);
349349
void nfs_zap_acl_cache(struct inode *inode);
350-
extern int nfs_wait_bit_killable(void *word);
350+
extern int nfs_wait_bit_killable(struct wait_bit_key *key);
351351

352352
/* super.c */
353353
extern const struct super_operations nfs_sops;

fs/nfs/pagelist.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ __nfs_iocounter_wait(struct nfs_io_counter *c)
117117
set_bit(NFS_IO_INPROGRESS, &c->flags);
118118
if (atomic_read(&c->io_count) == 0)
119119
break;
120-
ret = nfs_wait_bit_killable(&c->flags);
120+
ret = nfs_wait_bit_killable(&q.key);
121121
} while (atomic_read(&c->io_count) != 0);
122122
finish_wait(wq, &q.wait);
123123
return ret;

include/linux/sunrpc/sched.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ void * rpc_malloc(struct rpc_task *, size_t);
236236
void rpc_free(void *);
237237
int rpciod_up(void);
238238
void rpciod_down(void);
239-
int __rpc_wait_for_completion_task(struct rpc_task *task, int (*)(void *));
239+
int __rpc_wait_for_completion_task(struct rpc_task *task, wait_bit_action_f *);
240240
#ifdef RPC_DEBUG
241241
struct net;
242242
void rpc_show_tasks(struct net *);

include/linux/wait.h

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ struct wait_bit_key {
2525
void *flags;
2626
int bit_nr;
2727
#define WAIT_ATOMIC_T_BIT_NR -1
28+
unsigned long private;
2829
};
2930

3031
struct wait_bit_queue {
@@ -141,18 +142,19 @@ __remove_wait_queue(wait_queue_head_t *head, wait_queue_t *old)
141142
list_del(&old->task_list);
142143
}
143144

145+
typedef int wait_bit_action_f(struct wait_bit_key *);
144146
void __wake_up(wait_queue_head_t *q, unsigned int mode, int nr, void *key);
145147
void __wake_up_locked_key(wait_queue_head_t *q, unsigned int mode, void *key);
146148
void __wake_up_sync_key(wait_queue_head_t *q, unsigned int mode, int nr, void *key);
147149
void __wake_up_locked(wait_queue_head_t *q, unsigned int mode, int nr);
148150
void __wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr);
149151
void __wake_up_bit(wait_queue_head_t *, void *, int);
150-
int __wait_on_bit(wait_queue_head_t *, struct wait_bit_queue *, int (*)(void *), unsigned);
151-
int __wait_on_bit_lock(wait_queue_head_t *, struct wait_bit_queue *, int (*)(void *), unsigned);
152+
int __wait_on_bit(wait_queue_head_t *, struct wait_bit_queue *, wait_bit_action_f *, unsigned);
153+
int __wait_on_bit_lock(wait_queue_head_t *, struct wait_bit_queue *, wait_bit_action_f *, unsigned);
152154
void wake_up_bit(void *, int);
153155
void wake_up_atomic_t(atomic_t *);
154-
int out_of_line_wait_on_bit(void *, int, int (*)(void *), unsigned);
155-
int out_of_line_wait_on_bit_lock(void *, int, int (*)(void *), unsigned);
156+
int out_of_line_wait_on_bit(void *, int, wait_bit_action_f *, unsigned);
157+
int out_of_line_wait_on_bit_lock(void *, int, wait_bit_action_f *, unsigned);
156158
int out_of_line_wait_on_atomic_t(atomic_t *, int (*)(atomic_t *), unsigned);
157159
wait_queue_head_t *bit_waitqueue(void *, int);
158160

@@ -855,8 +857,8 @@ int wake_bit_function(wait_queue_t *wait, unsigned mode, int sync, void *key);
855857
} while (0)
856858

857859

858-
extern int bit_wait(void *);
859-
extern int bit_wait_io(void *);
860+
extern int bit_wait(struct wait_bit_key *);
861+
extern int bit_wait_io(struct wait_bit_key *);
860862

861863
/**
862864
* wait_on_bit - wait for a bit to be cleared
@@ -925,7 +927,7 @@ wait_on_bit_io(void *word, int bit, unsigned mode)
925927
* on that signal.
926928
*/
927929
static inline int
928-
wait_on_bit_action(void *word, int bit, int (*action)(void *), unsigned mode)
930+
wait_on_bit_action(void *word, int bit, wait_bit_action_f *action, unsigned mode)
929931
{
930932
if (!test_bit(bit, word))
931933
return 0;
@@ -1000,7 +1002,7 @@ wait_on_bit_lock_io(void *word, int bit, unsigned mode)
10001002
* the @mode allows that signal to wake the process.
10011003
*/
10021004
static inline int
1003-
wait_on_bit_lock_action(void *word, int bit, int (*action)(void *), unsigned mode)
1005+
wait_on_bit_lock_action(void *word, int bit, wait_bit_action_f *action, unsigned mode)
10041006
{
10051007
if (!test_and_set_bit(bit, word))
10061008
return 0;

kernel/sched/wait.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -319,22 +319,22 @@ EXPORT_SYMBOL(wake_bit_function);
319319
*/
320320
int __sched
321321
__wait_on_bit(wait_queue_head_t *wq, struct wait_bit_queue *q,
322-
int (*action)(void *), unsigned mode)
322+
wait_bit_action_f *action, unsigned mode)
323323
{
324324
int ret = 0;
325325

326326
do {
327327
prepare_to_wait(wq, &q->wait, mode);
328328
if (test_bit(q->key.bit_nr, q->key.flags))
329-
ret = (*action)(q->key.flags);
329+
ret = (*action)(&q->key);
330330
} while (test_bit(q->key.bit_nr, q->key.flags) && !ret);
331331
finish_wait(wq, &q->wait);
332332
return ret;
333333
}
334334
EXPORT_SYMBOL(__wait_on_bit);
335335

336336
int __sched out_of_line_wait_on_bit(void *word, int bit,
337-
int (*action)(void *), unsigned mode)
337+
wait_bit_action_f *action, unsigned mode)
338338
{
339339
wait_queue_head_t *wq = bit_waitqueue(word, bit);
340340
DEFINE_WAIT_BIT(wait, word, bit);
@@ -345,15 +345,15 @@ EXPORT_SYMBOL(out_of_line_wait_on_bit);
345345

346346
int __sched
347347
__wait_on_bit_lock(wait_queue_head_t *wq, struct wait_bit_queue *q,
348-
int (*action)(void *), unsigned mode)
348+
wait_bit_action_f *action, unsigned mode)
349349
{
350350
do {
351351
int ret;
352352

353353
prepare_to_wait_exclusive(wq, &q->wait, mode);
354354
if (!test_bit(q->key.bit_nr, q->key.flags))
355355
continue;
356-
ret = action(q->key.flags);
356+
ret = action(&q->key);
357357
if (!ret)
358358
continue;
359359
abort_exclusive_wait(wq, &q->wait, mode, &q->key);
@@ -365,7 +365,7 @@ __wait_on_bit_lock(wait_queue_head_t *wq, struct wait_bit_queue *q,
365365
EXPORT_SYMBOL(__wait_on_bit_lock);
366366

367367
int __sched out_of_line_wait_on_bit_lock(void *word, int bit,
368-
int (*action)(void *), unsigned mode)
368+
wait_bit_action_f *action, unsigned mode)
369369
{
370370
wait_queue_head_t *wq = bit_waitqueue(word, bit);
371371
DEFINE_WAIT_BIT(wait, word, bit);
@@ -503,7 +503,7 @@ void wake_up_atomic_t(atomic_t *p)
503503
}
504504
EXPORT_SYMBOL(wake_up_atomic_t);
505505

506-
__sched int bit_wait(void *word)
506+
__sched int bit_wait(struct wait_bit_key *word)
507507
{
508508
if (signal_pending_state(current->state, current))
509509
return 1;
@@ -512,7 +512,7 @@ __sched int bit_wait(void *word)
512512
}
513513
EXPORT_SYMBOL(bit_wait);
514514

515-
__sched int bit_wait_io(void *word)
515+
__sched int bit_wait_io(struct wait_bit_key *word)
516516
{
517517
if (signal_pending_state(current->state, current))
518518
return 1;

net/sunrpc/sched.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ void rpc_destroy_wait_queue(struct rpc_wait_queue *queue)
250250
}
251251
EXPORT_SYMBOL_GPL(rpc_destroy_wait_queue);
252252

253-
static int rpc_wait_bit_killable(void *word)
253+
static int rpc_wait_bit_killable(struct wait_bit_key *key)
254254
{
255255
if (fatal_signal_pending(current))
256256
return -ERESTARTSYS;
@@ -309,7 +309,7 @@ static int rpc_complete_task(struct rpc_task *task)
309309
* to enforce taking of the wq->lock and hence avoid races with
310310
* rpc_complete_task().
311311
*/
312-
int __rpc_wait_for_completion_task(struct rpc_task *task, int (*action)(void *))
312+
int __rpc_wait_for_completion_task(struct rpc_task *task, wait_bit_action_f *action)
313313
{
314314
if (action == NULL)
315315
action = rpc_wait_bit_killable;

0 commit comments

Comments
 (0)