diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/workqueue.c | 36 |
1 files changed, 13 insertions, 23 deletions
diff --git a/kernel/workqueue.c b/kernel/workqueue.c index c11edc9c9365..e5cb7faac58e 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c | |||
| @@ -468,10 +468,9 @@ static int work_next_color(int color) | |||
| 468 | } | 468 | } |
| 469 | 469 | ||
| 470 | /* | 470 | /* |
| 471 | * Work data points to the cwq while a work is on queue. Once | 471 | * A work's data points to the cwq with WORK_STRUCT_CWQ set while the |
| 472 | * execution starts, it points to the cpu the work was last on. This | 472 | * work is on queue. Once execution starts, WORK_STRUCT_CWQ is |
| 473 | * can be distinguished by comparing the data value against | 473 | * cleared and the work data contains the cpu number it was last on. |
| 474 | * PAGE_OFFSET. | ||
| 475 | * | 474 | * |
| 476 | * set_work_{cwq|cpu}() and clear_work_data() can be used to set the | 475 | * set_work_{cwq|cpu}() and clear_work_data() can be used to set the |
| 477 | * cwq, cpu or clear work->data. These functions should only be | 476 | * cwq, cpu or clear work->data. These functions should only be |
| @@ -494,7 +493,7 @@ static void set_work_cwq(struct work_struct *work, | |||
| 494 | unsigned long extra_flags) | 493 | unsigned long extra_flags) |
| 495 | { | 494 | { |
| 496 | set_work_data(work, (unsigned long)cwq, | 495 | set_work_data(work, (unsigned long)cwq, |
| 497 | WORK_STRUCT_PENDING | extra_flags); | 496 | WORK_STRUCT_PENDING | WORK_STRUCT_CWQ | extra_flags); |
| 498 | } | 497 | } |
| 499 | 498 | ||
| 500 | static void set_work_cpu(struct work_struct *work, unsigned int cpu) | 499 | static void set_work_cpu(struct work_struct *work, unsigned int cpu) |
| @@ -507,25 +506,24 @@ static void clear_work_data(struct work_struct *work) | |||
| 507 | set_work_data(work, WORK_STRUCT_NO_CPU, 0); | 506 | set_work_data(work, WORK_STRUCT_NO_CPU, 0); |
| 508 | } | 507 | } |
| 509 | 508 | ||
| 510 | static inline unsigned long get_work_data(struct work_struct *work) | ||
| 511 | { | ||
| 512 | return atomic_long_read(&work->data) & WORK_STRUCT_WQ_DATA_MASK; | ||
| 513 | } | ||
| 514 | |||
| 515 | static struct cpu_workqueue_struct *get_work_cwq(struct work_struct *work) | 509 | static struct cpu_workqueue_struct *get_work_cwq(struct work_struct *work) |
| 516 | { | 510 | { |
| 517 | unsigned long data = get_work_data(work); | 511 | unsigned long data = atomic_long_read(&work->data); |
| 518 | 512 | ||
| 519 | return data >= PAGE_OFFSET ? (void *)data : NULL; | 513 | if (data & WORK_STRUCT_CWQ) |
| 514 | return (void *)(data & WORK_STRUCT_WQ_DATA_MASK); | ||
| 515 | else | ||
| 516 | return NULL; | ||
| 520 | } | 517 | } |
| 521 | 518 | ||
| 522 | static struct global_cwq *get_work_gcwq(struct work_struct *work) | 519 | static struct global_cwq *get_work_gcwq(struct work_struct *work) |
| 523 | { | 520 | { |
| 524 | unsigned long data = get_work_data(work); | 521 | unsigned long data = atomic_long_read(&work->data); |
| 525 | unsigned int cpu; | 522 | unsigned int cpu; |
| 526 | 523 | ||
| 527 | if (data >= PAGE_OFFSET) | 524 | if (data & WORK_STRUCT_CWQ) |
| 528 | return ((struct cpu_workqueue_struct *)data)->gcwq; | 525 | return ((struct cpu_workqueue_struct *) |
| 526 | (data & WORK_STRUCT_WQ_DATA_MASK))->gcwq; | ||
| 529 | 527 | ||
| 530 | cpu = data >> WORK_STRUCT_FLAG_BITS; | 528 | cpu = data >> WORK_STRUCT_FLAG_BITS; |
| 531 | if (cpu == WORK_CPU_NONE) | 529 | if (cpu == WORK_CPU_NONE) |
| @@ -3501,14 +3499,6 @@ void __init init_workqueues(void) | |||
| 3501 | unsigned int cpu; | 3499 | unsigned int cpu; |
| 3502 | int i; | 3500 | int i; |
| 3503 | 3501 | ||
| 3504 | /* | ||
| 3505 | * The pointer part of work->data is either pointing to the | ||
| 3506 | * cwq or contains the cpu number the work ran last on. Make | ||
| 3507 | * sure cpu number won't overflow into kernel pointer area so | ||
| 3508 | * that they can be distinguished. | ||
| 3509 | */ | ||
| 3510 | BUILD_BUG_ON(WORK_CPU_LAST << WORK_STRUCT_FLAG_BITS >= PAGE_OFFSET); | ||
| 3511 | |||
| 3512 | hotcpu_notifier(workqueue_cpu_callback, CPU_PRI_WORKQUEUE); | 3502 | hotcpu_notifier(workqueue_cpu_callback, CPU_PRI_WORKQUEUE); |
| 3513 | 3503 | ||
| 3514 | /* initialize gcwqs */ | 3504 | /* initialize gcwqs */ |
