diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-02 12:52:47 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-02 12:52:47 -0400 |
| commit | bcd7351e83728859833e3c5b8aae9a2816914e4b (patch) | |
| tree | 940487a8b04f6ec79212836954d9c1389a9d80ed /include/linux | |
| parent | 6072a93b98e660211c4b46a8381833425bdcf7b7 (diff) | |
| parent | dcfae32f892f03dee9896b19d1960c1ecd3f0583 (diff) | |
Merge tag 'fscache-20130702' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs
Pull FS-Cache updates from David Howells:
"This contains a number of fixes for various FS-Cache issues plus some
cleanups. The commits are, in order:
1) Provide a system wait_on_atomic_t() and wake_up_atomic_t() sharing
the bit-wait table (enhancement for #8).
2) Don't put spin_lock() in a while-condition as spin_lock() may have
a do {} while(0) wrapper (cleanup).
3) Symbolically name i_mutex lock classes rather than using numbers
in CacheFiles (cleanup).
4) Don't sleep in page release if __GFP_FS is not set (deadlock vs
ext4).
5) Uninline fscache_object_init() (cleanup for #7).
6) Wrap checks on object state (cleanup for #7).
7) Simplify the object state machine by separating work states from
wait states.
8) Simplify cookie retention by objects (NULL pointer deref fix).
9) Remove unused list_to_page() macro (cleanup).
10) Make the remaining-pages counter in the retrieval op atomic
(assertion failure fix).
11) Don't use spin_is_locked() in assertions (assertion failure fix)"
* tag 'fscache-20130702' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs:
FS-Cache: Don't use spin_is_locked() in assertions
FS-Cache: The retrieval remaining-pages counter needs to be atomic_t
cachefiles: remove unused macro list_to_page()
FS-Cache: Simplify cookie retention for fscache_objects, fixing oops
FS-Cache: Fix object state machine to have separate work and wait states
FS-Cache: Wrap checks on object state
FS-Cache: Uninline fscache_object_init()
FS-Cache: Don't sleep in page release if __GFP_FS is not set
CacheFiles: name i_mutex lock class explicitly
fs/fscache: remove spin_lock() from the condition in while()
Add wait_on_atomic_t() and wake_up_atomic_t()
Diffstat (limited to 'include/linux')
| -rw-r--r-- | include/linux/fscache-cache.h | 175 | ||||
| -rw-r--r-- | include/linux/wait.h | 24 |
2 files changed, 113 insertions, 86 deletions
diff --git a/include/linux/fscache-cache.h b/include/linux/fscache-cache.h index 5dfa0aa216b6..a9ff9a36b86d 100644 --- a/include/linux/fscache-cache.h +++ b/include/linux/fscache-cache.h | |||
| @@ -97,7 +97,8 @@ struct fscache_operation { | |||
| 97 | #define FSCACHE_OP_WAITING 4 /* cleared when op is woken */ | 97 | #define FSCACHE_OP_WAITING 4 /* cleared when op is woken */ |
| 98 | #define FSCACHE_OP_EXCLUSIVE 5 /* exclusive op, other ops must wait */ | 98 | #define FSCACHE_OP_EXCLUSIVE 5 /* exclusive op, other ops must wait */ |
| 99 | #define FSCACHE_OP_DEC_READ_CNT 6 /* decrement object->n_reads on destruction */ | 99 | #define FSCACHE_OP_DEC_READ_CNT 6 /* decrement object->n_reads on destruction */ |
| 100 | #define FSCACHE_OP_KEEP_FLAGS 0x0070 /* flags to keep when repurposing an op */ | 100 | #define FSCACHE_OP_UNUSE_COOKIE 7 /* call fscache_unuse_cookie() on completion */ |
| 101 | #define FSCACHE_OP_KEEP_FLAGS 0x00f0 /* flags to keep when repurposing an op */ | ||
| 101 | 102 | ||
| 102 | enum fscache_operation_state state; | 103 | enum fscache_operation_state state; |
| 103 | atomic_t usage; | 104 | atomic_t usage; |
| @@ -150,7 +151,7 @@ struct fscache_retrieval { | |||
| 150 | void *context; /* netfs read context (pinned) */ | 151 | void *context; /* netfs read context (pinned) */ |
| 151 | struct list_head to_do; /* list of things to be done by the backend */ | 152 | struct list_head to_do; /* list of things to be done by the backend */ |
| 152 | unsigned long start_time; /* time at which retrieval started */ | 153 | unsigned long start_time; /* time at which retrieval started */ |
| 153 | unsigned n_pages; /* number of pages to be retrieved */ | 154 | atomic_t n_pages; /* number of pages to be retrieved */ |
| 154 | }; | 155 | }; |
| 155 | 156 | ||
| 156 | typedef int (*fscache_page_retrieval_func_t)(struct fscache_retrieval *op, | 157 | typedef int (*fscache_page_retrieval_func_t)(struct fscache_retrieval *op, |
| @@ -194,15 +195,14 @@ static inline void fscache_enqueue_retrieval(struct fscache_retrieval *op) | |||
| 194 | static inline void fscache_retrieval_complete(struct fscache_retrieval *op, | 195 | static inline void fscache_retrieval_complete(struct fscache_retrieval *op, |
| 195 | int n_pages) | 196 | int n_pages) |
| 196 | { | 197 | { |
| 197 | op->n_pages -= n_pages; | 198 | atomic_sub(n_pages, &op->n_pages); |
| 198 | if (op->n_pages <= 0) | 199 | if (atomic_read(&op->n_pages) <= 0) |
| 199 | fscache_op_complete(&op->op, true); | 200 | fscache_op_complete(&op->op, true); |
| 200 | } | 201 | } |
| 201 | 202 | ||
| 202 | /** | 203 | /** |
| 203 | * fscache_put_retrieval - Drop a reference to a retrieval operation | 204 | * fscache_put_retrieval - Drop a reference to a retrieval operation |
| 204 | * @op: The retrieval operation affected | 205 | * @op: The retrieval operation affected |
| 205 | * @n_pages: The number of pages to account for | ||
| 206 | * | 206 | * |
| 207 | * Drop a reference to a retrieval operation. | 207 | * Drop a reference to a retrieval operation. |
| 208 | */ | 208 | */ |
| @@ -314,6 +314,7 @@ struct fscache_cache_ops { | |||
| 314 | struct fscache_cookie { | 314 | struct fscache_cookie { |
| 315 | atomic_t usage; /* number of users of this cookie */ | 315 | atomic_t usage; /* number of users of this cookie */ |
| 316 | atomic_t n_children; /* number of children of this cookie */ | 316 | atomic_t n_children; /* number of children of this cookie */ |
| 317 | atomic_t n_active; /* number of active users of netfs ptrs */ | ||
| 317 | spinlock_t lock; | 318 | spinlock_t lock; |
| 318 | spinlock_t stores_lock; /* lock on page store tree */ | 319 | spinlock_t stores_lock; /* lock on page store tree */ |
| 319 | struct hlist_head backing_objects; /* object(s) backing this file/index */ | 320 | struct hlist_head backing_objects; /* object(s) backing this file/index */ |
| @@ -326,13 +327,11 @@ struct fscache_cookie { | |||
| 326 | 327 | ||
| 327 | unsigned long flags; | 328 | unsigned long flags; |
| 328 | #define FSCACHE_COOKIE_LOOKING_UP 0 /* T if non-index cookie being looked up still */ | 329 | #define FSCACHE_COOKIE_LOOKING_UP 0 /* T if non-index cookie being looked up still */ |
| 329 | #define FSCACHE_COOKIE_CREATING 1 /* T if non-index object being created still */ | 330 | #define FSCACHE_COOKIE_NO_DATA_YET 1 /* T if new object with no cached data yet */ |
| 330 | #define FSCACHE_COOKIE_NO_DATA_YET 2 /* T if new object with no cached data yet */ | 331 | #define FSCACHE_COOKIE_UNAVAILABLE 2 /* T if cookie is unavailable (error, etc) */ |
| 331 | #define FSCACHE_COOKIE_PENDING_FILL 3 /* T if pending initial fill on object */ | 332 | #define FSCACHE_COOKIE_INVALIDATING 3 /* T if cookie is being invalidated */ |
| 332 | #define FSCACHE_COOKIE_FILLING 4 /* T if filling object incrementally */ | 333 | #define FSCACHE_COOKIE_RELINQUISHED 4 /* T if cookie has been relinquished */ |
| 333 | #define FSCACHE_COOKIE_UNAVAILABLE 5 /* T if cookie is unavailable (error, etc) */ | 334 | #define FSCACHE_COOKIE_RETIRED 5 /* T if cookie was retired */ |
| 334 | #define FSCACHE_COOKIE_WAITING_ON_READS 6 /* T if cookie is waiting on reads */ | ||
| 335 | #define FSCACHE_COOKIE_INVALIDATING 7 /* T if cookie is being invalidated */ | ||
| 336 | }; | 335 | }; |
| 337 | 336 | ||
| 338 | extern struct fscache_cookie fscache_fsdef_index; | 337 | extern struct fscache_cookie fscache_fsdef_index; |
| @@ -341,45 +340,40 @@ extern struct fscache_cookie fscache_fsdef_index; | |||
| 341 | * Event list for fscache_object::{event_mask,events} | 340 | * Event list for fscache_object::{event_mask,events} |
| 342 | */ | 341 | */ |
| 343 | enum { | 342 | enum { |
| 344 | FSCACHE_OBJECT_EV_REQUEUE, /* T if object should be requeued */ | 343 | FSCACHE_OBJECT_EV_NEW_CHILD, /* T if object has a new child */ |
| 344 | FSCACHE_OBJECT_EV_PARENT_READY, /* T if object's parent is ready */ | ||
| 345 | FSCACHE_OBJECT_EV_UPDATE, /* T if object should be updated */ | 345 | FSCACHE_OBJECT_EV_UPDATE, /* T if object should be updated */ |
| 346 | FSCACHE_OBJECT_EV_INVALIDATE, /* T if cache requested object invalidation */ | 346 | FSCACHE_OBJECT_EV_INVALIDATE, /* T if cache requested object invalidation */ |
| 347 | FSCACHE_OBJECT_EV_CLEARED, /* T if accessors all gone */ | 347 | FSCACHE_OBJECT_EV_CLEARED, /* T if accessors all gone */ |
| 348 | FSCACHE_OBJECT_EV_ERROR, /* T if fatal error occurred during processing */ | 348 | FSCACHE_OBJECT_EV_ERROR, /* T if fatal error occurred during processing */ |
| 349 | FSCACHE_OBJECT_EV_RELEASE, /* T if netfs requested object release */ | 349 | FSCACHE_OBJECT_EV_KILL, /* T if netfs relinquished or cache withdrew object */ |
| 350 | FSCACHE_OBJECT_EV_RETIRE, /* T if netfs requested object retirement */ | ||
| 351 | FSCACHE_OBJECT_EV_WITHDRAW, /* T if cache requested object withdrawal */ | ||
| 352 | NR_FSCACHE_OBJECT_EVENTS | 350 | NR_FSCACHE_OBJECT_EVENTS |
| 353 | }; | 351 | }; |
| 354 | 352 | ||
| 355 | #define FSCACHE_OBJECT_EVENTS_MASK ((1UL << NR_FSCACHE_OBJECT_EVENTS) - 1) | 353 | #define FSCACHE_OBJECT_EVENTS_MASK ((1UL << NR_FSCACHE_OBJECT_EVENTS) - 1) |
| 356 | 354 | ||
| 357 | /* | 355 | /* |
| 356 | * States for object state machine. | ||
| 357 | */ | ||
| 358 | struct fscache_transition { | ||
| 359 | unsigned long events; | ||
| 360 | const struct fscache_state *transit_to; | ||
| 361 | }; | ||
| 362 | |||
| 363 | struct fscache_state { | ||
| 364 | char name[24]; | ||
| 365 | char short_name[8]; | ||
| 366 | const struct fscache_state *(*work)(struct fscache_object *object, | ||
| 367 | int event); | ||
| 368 | const struct fscache_transition transitions[]; | ||
| 369 | }; | ||
| 370 | |||
| 371 | /* | ||
| 358 | * on-disk cache file or index handle | 372 | * on-disk cache file or index handle |
| 359 | */ | 373 | */ |
| 360 | struct fscache_object { | 374 | struct fscache_object { |
| 361 | enum fscache_object_state { | 375 | const struct fscache_state *state; /* Object state machine state */ |
| 362 | FSCACHE_OBJECT_INIT, /* object in initial unbound state */ | 376 | const struct fscache_transition *oob_table; /* OOB state transition table */ |
| 363 | FSCACHE_OBJECT_LOOKING_UP, /* looking up object */ | ||
| 364 | FSCACHE_OBJECT_CREATING, /* creating object */ | ||
| 365 | |||
| 366 | /* active states */ | ||
| 367 | FSCACHE_OBJECT_AVAILABLE, /* cleaning up object after creation */ | ||
| 368 | FSCACHE_OBJECT_ACTIVE, /* object is usable */ | ||
| 369 | FSCACHE_OBJECT_INVALIDATING, /* object is invalidating */ | ||
| 370 | FSCACHE_OBJECT_UPDATING, /* object is updating */ | ||
| 371 | |||
| 372 | /* terminal states */ | ||
| 373 | FSCACHE_OBJECT_DYING, /* object waiting for accessors to finish */ | ||
| 374 | FSCACHE_OBJECT_LC_DYING, /* object cleaning up after lookup/create */ | ||
| 375 | FSCACHE_OBJECT_ABORT_INIT, /* abort the init state */ | ||
| 376 | FSCACHE_OBJECT_RELEASING, /* releasing object */ | ||
| 377 | FSCACHE_OBJECT_RECYCLING, /* retiring object */ | ||
| 378 | FSCACHE_OBJECT_WITHDRAWING, /* withdrawing object */ | ||
| 379 | FSCACHE_OBJECT_DEAD, /* object is now dead */ | ||
| 380 | FSCACHE_OBJECT__NSTATES | ||
| 381 | } state; | ||
| 382 | |||
| 383 | int debug_id; /* debugging ID */ | 377 | int debug_id; /* debugging ID */ |
| 384 | int n_children; /* number of child objects */ | 378 | int n_children; /* number of child objects */ |
| 385 | int n_ops; /* number of extant ops on object */ | 379 | int n_ops; /* number of extant ops on object */ |
| @@ -390,6 +384,7 @@ struct fscache_object { | |||
| 390 | spinlock_t lock; /* state and operations lock */ | 384 | spinlock_t lock; /* state and operations lock */ |
| 391 | 385 | ||
| 392 | unsigned long lookup_jif; /* time at which lookup started */ | 386 | unsigned long lookup_jif; /* time at which lookup started */ |
| 387 | unsigned long oob_event_mask; /* OOB events this object is interested in */ | ||
| 393 | unsigned long event_mask; /* events this object is interested in */ | 388 | unsigned long event_mask; /* events this object is interested in */ |
| 394 | unsigned long events; /* events to be processed by this object | 389 | unsigned long events; /* events to be processed by this object |
| 395 | * (order is important - using fls) */ | 390 | * (order is important - using fls) */ |
| @@ -398,6 +393,9 @@ struct fscache_object { | |||
| 398 | #define FSCACHE_OBJECT_LOCK 0 /* T if object is busy being processed */ | 393 | #define FSCACHE_OBJECT_LOCK 0 /* T if object is busy being processed */ |
| 399 | #define FSCACHE_OBJECT_PENDING_WRITE 1 /* T if object has pending write */ | 394 | #define FSCACHE_OBJECT_PENDING_WRITE 1 /* T if object has pending write */ |
| 400 | #define FSCACHE_OBJECT_WAITING 2 /* T if object is waiting on its parent */ | 395 | #define FSCACHE_OBJECT_WAITING 2 /* T if object is waiting on its parent */ |
| 396 | #define FSCACHE_OBJECT_IS_LIVE 3 /* T if object is not withdrawn or relinquished */ | ||
| 397 | #define FSCACHE_OBJECT_IS_LOOKED_UP 4 /* T if object has been looked up */ | ||
| 398 | #define FSCACHE_OBJECT_IS_AVAILABLE 5 /* T if object has become active */ | ||
| 401 | 399 | ||
| 402 | struct list_head cache_link; /* link in cache->object_list */ | 400 | struct list_head cache_link; /* link in cache->object_list */ |
| 403 | struct hlist_node cookie_link; /* link in cookie->backing_objects */ | 401 | struct hlist_node cookie_link; /* link in cookie->backing_objects */ |
| @@ -415,62 +413,40 @@ struct fscache_object { | |||
| 415 | loff_t store_limit_l; /* current storage limit */ | 413 | loff_t store_limit_l; /* current storage limit */ |
| 416 | }; | 414 | }; |
| 417 | 415 | ||
| 418 | extern const char *fscache_object_states[]; | 416 | extern void fscache_object_init(struct fscache_object *, struct fscache_cookie *, |
| 417 | struct fscache_cache *); | ||
| 418 | extern void fscache_object_destroy(struct fscache_object *); | ||
| 419 | 419 | ||
| 420 | #define fscache_object_is_active(obj) \ | 420 | extern void fscache_object_lookup_negative(struct fscache_object *object); |
| 421 | (!test_bit(FSCACHE_IOERROR, &(obj)->cache->flags) && \ | 421 | extern void fscache_obtained_object(struct fscache_object *object); |
| 422 | (obj)->state >= FSCACHE_OBJECT_AVAILABLE && \ | ||
| 423 | (obj)->state < FSCACHE_OBJECT_DYING) | ||
| 424 | 422 | ||
| 425 | #define fscache_object_is_dead(obj) \ | 423 | static inline bool fscache_object_is_live(struct fscache_object *object) |
| 426 | (test_bit(FSCACHE_IOERROR, &(obj)->cache->flags) && \ | 424 | { |
| 427 | (obj)->state >= FSCACHE_OBJECT_DYING) | 425 | return test_bit(FSCACHE_OBJECT_IS_LIVE, &object->flags); |
| 426 | } | ||
| 428 | 427 | ||
| 429 | extern void fscache_object_work_func(struct work_struct *work); | 428 | static inline bool fscache_object_is_dying(struct fscache_object *object) |
| 429 | { | ||
| 430 | return !fscache_object_is_live(object); | ||
| 431 | } | ||
| 430 | 432 | ||
| 431 | /** | 433 | static inline bool fscache_object_is_available(struct fscache_object *object) |
| 432 | * fscache_object_init - Initialise a cache object description | ||
| 433 | * @object: Object description | ||
| 434 | * | ||
| 435 | * Initialise a cache object description to its basic values. | ||
| 436 | * | ||
| 437 | * See Documentation/filesystems/caching/backend-api.txt for a complete | ||
| 438 | * description. | ||
| 439 | */ | ||
| 440 | static inline | ||
| 441 | void fscache_object_init(struct fscache_object *object, | ||
| 442 | struct fscache_cookie *cookie, | ||
| 443 | struct fscache_cache *cache) | ||
| 444 | { | 434 | { |
| 445 | atomic_inc(&cache->object_count); | 435 | return test_bit(FSCACHE_OBJECT_IS_AVAILABLE, &object->flags); |
| 446 | |||
| 447 | object->state = FSCACHE_OBJECT_INIT; | ||
| 448 | spin_lock_init(&object->lock); | ||
| 449 | INIT_LIST_HEAD(&object->cache_link); | ||
| 450 | INIT_HLIST_NODE(&object->cookie_link); | ||
| 451 | INIT_WORK(&object->work, fscache_object_work_func); | ||
| 452 | INIT_LIST_HEAD(&object->dependents); | ||
| 453 | INIT_LIST_HEAD(&object->dep_link); | ||
| 454 | INIT_LIST_HEAD(&object->pending_ops); | ||
| 455 | object->n_children = 0; | ||
| 456 | object->n_ops = object->n_in_progress = object->n_exclusive = 0; | ||
| 457 | object->events = object->event_mask = 0; | ||
| 458 | object->flags = 0; | ||
| 459 | object->store_limit = 0; | ||
| 460 | object->store_limit_l = 0; | ||
| 461 | object->cache = cache; | ||
| 462 | object->cookie = cookie; | ||
| 463 | object->parent = NULL; | ||
| 464 | } | 436 | } |
| 465 | 437 | ||
| 466 | extern void fscache_object_lookup_negative(struct fscache_object *object); | 438 | static inline bool fscache_object_is_active(struct fscache_object *object) |
| 467 | extern void fscache_obtained_object(struct fscache_object *object); | 439 | { |
| 440 | return fscache_object_is_available(object) && | ||
| 441 | fscache_object_is_live(object) && | ||
| 442 | !test_bit(FSCACHE_IOERROR, &object->cache->flags); | ||
| 443 | } | ||
| 468 | 444 | ||
| 469 | #ifdef CONFIG_FSCACHE_OBJECT_LIST | 445 | static inline bool fscache_object_is_dead(struct fscache_object *object) |
| 470 | extern void fscache_object_destroy(struct fscache_object *object); | 446 | { |
| 471 | #else | 447 | return fscache_object_is_dying(object) && |
| 472 | #define fscache_object_destroy(object) do {} while(0) | 448 | test_bit(FSCACHE_IOERROR, &object->cache->flags); |
| 473 | #endif | 449 | } |
| 474 | 450 | ||
| 475 | /** | 451 | /** |
| 476 | * fscache_object_destroyed - Note destruction of an object in a cache | 452 | * fscache_object_destroyed - Note destruction of an object in a cache |
| @@ -531,6 +507,33 @@ static inline void fscache_end_io(struct fscache_retrieval *op, | |||
| 531 | op->end_io_func(page, op->context, error); | 507 | op->end_io_func(page, op->context, error); |
| 532 | } | 508 | } |
| 533 | 509 | ||
| 510 | /** | ||
| 511 | * fscache_use_cookie - Request usage of cookie attached to an object | ||
| 512 | * @object: Object description | ||
| 513 | * | ||
| 514 | * Request usage of the cookie attached to an object. NULL is returned if the | ||
| 515 | * relinquishment had reduced the cookie usage count to 0. | ||
| 516 | */ | ||
| 517 | static inline bool fscache_use_cookie(struct fscache_object *object) | ||
| 518 | { | ||
| 519 | struct fscache_cookie *cookie = object->cookie; | ||
| 520 | return atomic_inc_not_zero(&cookie->n_active) != 0; | ||
| 521 | } | ||
| 522 | |||
| 523 | /** | ||
| 524 | * fscache_unuse_cookie - Cease usage of cookie attached to an object | ||
| 525 | * @object: Object description | ||
| 526 | * | ||
| 527 | * Cease usage of the cookie attached to an object. When the users count | ||
| 528 | * reaches zero then the cookie relinquishment will be permitted to proceed. | ||
| 529 | */ | ||
| 530 | static inline void fscache_unuse_cookie(struct fscache_object *object) | ||
| 531 | { | ||
| 532 | struct fscache_cookie *cookie = object->cookie; | ||
| 533 | if (atomic_dec_and_test(&cookie->n_active)) | ||
| 534 | wake_up_atomic_t(&cookie->n_active); | ||
| 535 | } | ||
| 536 | |||
| 534 | /* | 537 | /* |
| 535 | * out-of-line cache backend functions | 538 | * out-of-line cache backend functions |
| 536 | */ | 539 | */ |
diff --git a/include/linux/wait.h b/include/linux/wait.h index 1133695eb067..f487a4750b7f 100644 --- a/include/linux/wait.h +++ b/include/linux/wait.h | |||
| @@ -23,6 +23,7 @@ struct __wait_queue { | |||
| 23 | struct wait_bit_key { | 23 | struct wait_bit_key { |
| 24 | void *flags; | 24 | void *flags; |
| 25 | int bit_nr; | 25 | int bit_nr; |
| 26 | #define WAIT_ATOMIC_T_BIT_NR -1 | ||
| 26 | }; | 27 | }; |
| 27 | 28 | ||
| 28 | struct wait_bit_queue { | 29 | struct wait_bit_queue { |
| @@ -60,6 +61,9 @@ struct task_struct; | |||
| 60 | #define __WAIT_BIT_KEY_INITIALIZER(word, bit) \ | 61 | #define __WAIT_BIT_KEY_INITIALIZER(word, bit) \ |
| 61 | { .flags = word, .bit_nr = bit, } | 62 | { .flags = word, .bit_nr = bit, } |
| 62 | 63 | ||
| 64 | #define __WAIT_ATOMIC_T_KEY_INITIALIZER(p) \ | ||
| 65 | { .flags = p, .bit_nr = WAIT_ATOMIC_T_BIT_NR, } | ||
| 66 | |||
| 63 | extern void __init_waitqueue_head(wait_queue_head_t *q, const char *name, struct lock_class_key *); | 67 | extern void __init_waitqueue_head(wait_queue_head_t *q, const char *name, struct lock_class_key *); |
| 64 | 68 | ||
| 65 | #define init_waitqueue_head(q) \ | 69 | #define init_waitqueue_head(q) \ |
| @@ -146,8 +150,10 @@ void __wake_up_bit(wait_queue_head_t *, void *, int); | |||
| 146 | int __wait_on_bit(wait_queue_head_t *, struct wait_bit_queue *, int (*)(void *), unsigned); | 150 | int __wait_on_bit(wait_queue_head_t *, struct wait_bit_queue *, int (*)(void *), unsigned); |
| 147 | int __wait_on_bit_lock(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); |
| 148 | void wake_up_bit(void *, int); | 152 | void wake_up_bit(void *, int); |
| 153 | void wake_up_atomic_t(atomic_t *); | ||
| 149 | int out_of_line_wait_on_bit(void *, int, int (*)(void *), unsigned); | 154 | int out_of_line_wait_on_bit(void *, int, int (*)(void *), unsigned); |
| 150 | int out_of_line_wait_on_bit_lock(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_atomic_t(atomic_t *, int (*)(atomic_t *), unsigned); | ||
| 151 | wait_queue_head_t *bit_waitqueue(void *, int); | 157 | wait_queue_head_t *bit_waitqueue(void *, int); |
| 152 | 158 | ||
| 153 | #define wake_up(x) __wake_up(x, TASK_NORMAL, 1, NULL) | 159 | #define wake_up(x) __wake_up(x, TASK_NORMAL, 1, NULL) |
| @@ -902,5 +908,23 @@ static inline int wait_on_bit_lock(void *word, int bit, | |||
| 902 | return 0; | 908 | return 0; |
| 903 | return out_of_line_wait_on_bit_lock(word, bit, action, mode); | 909 | return out_of_line_wait_on_bit_lock(word, bit, action, mode); |
| 904 | } | 910 | } |
| 911 | |||
| 912 | /** | ||
| 913 | * wait_on_atomic_t - Wait for an atomic_t to become 0 | ||
| 914 | * @val: The atomic value being waited on, a kernel virtual address | ||
| 915 | * @action: the function used to sleep, which may take special actions | ||
| 916 | * @mode: the task state to sleep in | ||
| 917 | * | ||
| 918 | * Wait for an atomic_t to become 0. We abuse the bit-wait waitqueue table for | ||
| 919 | * the purpose of getting a waitqueue, but we set the key to a bit number | ||
| 920 | * outside of the target 'word'. | ||
| 921 | */ | ||
| 922 | static inline | ||
| 923 | int wait_on_atomic_t(atomic_t *val, int (*action)(atomic_t *), unsigned mode) | ||
| 924 | { | ||
| 925 | if (atomic_read(val) == 0) | ||
| 926 | return 0; | ||
| 927 | return out_of_line_wait_on_atomic_t(val, action, mode); | ||
| 928 | } | ||
| 905 | 929 | ||
| 906 | #endif | 930 | #endif |
