summaryrefslogtreecommitdiff
path: root/kernel/async.c
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2013-01-23 09:32:30 -0800
committerTejun Heo <tj@kernel.org>2013-01-23 09:32:30 -0800
commitc68eee14ec2da345e86f2778c8570759309a4a2e (patch)
tree953677198feb57ebd17b6d2c197cf8febc88a6c4 /kernel/async.c
parent8723d5037cafea09c7242303c6c8e5d7058cec61 (diff)
downloadlwn-c68eee14ec2da345e86f2778c8570759309a4a2e.tar.gz
lwn-c68eee14ec2da345e86f2778c8570759309a4a2e.zip
async: use ULLONG_MAX for infinity cookie value
Currently, next_cookie is used as the infinity value. In most cases, this should work fine but it theoretically could bring subtle behavior difference between async_synchronize_full() and async_synchronize_full_domain(). async_synchronize_full() keeps waiting until there's no registered async_entry left regardless of what next_cookie was when the function was called. It guarantees that the queue is completely drained at least once before returning. However, async_synchronize_full_domain() doesn't. It synchronizes upto next_cookie and if further async jobs are queued after the next_cookie value to synchronize is decided, they won't be waited for. For unrelated async jobs, the behavior difference doesn't matter; however, if async jobs which are related (nested or otherwise) to the executing ones are queued while sychronization is in progress, the resulting behavior difference could be problematic. This can be easily fixed by using ULLONG_MAX as the infinity value instead. Define ASYNC_COOKIE_MAX as ULLONG_MAX and use it as the infinity value for synchronization. This makes async_synchronize_full_domain() fully drain the domain at least once before returning, making its behavior match async_synchronize_full(). Signed-off-by: Tejun Heo <tj@kernel.org> Cc: Arjan van de Ven <arjan@linux.intel.com> Cc: Dan Williams <djbw@fb.com> Cc: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/async.c')
-rw-r--r--kernel/async.c11
1 files changed, 6 insertions, 5 deletions
diff --git a/kernel/async.c b/kernel/async.c
index 29d51d483bee..a4c1a9e63b2e 100644
--- a/kernel/async.c
+++ b/kernel/async.c
@@ -61,7 +61,8 @@ asynchronous and synchronous parts of the kernel.
static async_cookie_t next_cookie = 1;
-#define MAX_WORK 32768
+#define MAX_WORK 32768
+#define ASYNC_COOKIE_MAX ULLONG_MAX /* infinity cookie */
static LIST_HEAD(async_pending);
static ASYNC_DOMAIN(async_dfl_domain);
@@ -88,8 +89,8 @@ static atomic_t entry_count;
*/
static async_cookie_t __lowest_in_progress(struct async_domain *domain)
{
- async_cookie_t first_running = next_cookie; /* infinity value */
- async_cookie_t first_pending = next_cookie; /* ditto */
+ async_cookie_t first_running = ASYNC_COOKIE_MAX;
+ async_cookie_t first_pending = ASYNC_COOKIE_MAX;
struct async_entry *entry;
/*
@@ -269,7 +270,7 @@ void async_synchronize_full(void)
domain = list_first_entry(&async_domains, typeof(*domain), node);
spin_unlock_irq(&async_lock);
- async_synchronize_cookie_domain(next_cookie, domain);
+ async_synchronize_cookie_domain(ASYNC_COOKIE_MAX, domain);
} while (!list_empty(&async_domains));
mutex_unlock(&async_register_mutex);
}
@@ -305,7 +306,7 @@ EXPORT_SYMBOL_GPL(async_unregister_domain);
*/
void async_synchronize_full_domain(struct async_domain *domain)
{
- async_synchronize_cookie_domain(next_cookie, domain);
+ async_synchronize_cookie_domain(ASYNC_COOKIE_MAX, domain);
}
EXPORT_SYMBOL_GPL(async_synchronize_full_domain);