Skip to content

Commit afa4bb7

Browse files
committed
workqueue: clean up WORK_* constant types, clarify masking
Dave Airlie reports that gcc-13.1.1 has started complaining about some of the workqueue code in 32-bit arm builds: kernel/workqueue.c: In function ‘get_work_pwq’: kernel/workqueue.c:713:24: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast] 713 | return (void *)(data & WORK_STRUCT_WQ_DATA_MASK); | ^ [ ... a couple of other cases ... ] and while it's not immediately clear exactly why gcc started complaining about it now, I suspect it's some C23-induced enum type handlign fixup in gcc-13 is the cause. Whatever the reason for starting to complain, the code and data types are indeed disgusting enough that the complaint is warranted. The wq code ends up creating various "helper constants" (like that WORK_STRUCT_WQ_DATA_MASK) using an enum type, which is all kinds of confused. The mask needs to be 'unsigned long', not some unspecified enum type. To make matters worse, the actual "mask and cast to a pointer" is repeated a couple of times, and the cast isn't even always done to the right pointer, but - as the error case above - to a 'void *' with then the compiler finishing the job. That's now how we roll in the kernel. So create the masks using the proper types rather than some ambiguous enumeration, and use a nice helper that actually does the type conversion in one well-defined place. Incidentally, this magically makes clang generate better code. That, admittedly, is really just a sign of clang having been seriously confused before, and cleaning up the typing unconfuses the compiler too. Reported-by: Dave Airlie <airlied@gmail.com> Link: https://lore.kernel.org/lkml/CAPM=9twNnV4zMCvrPkw3H-ajZOH-01JVh_kDrxdPYQErz8ZTdA@mail.gmail.com/ Cc: Arnd Bergmann <arnd@arndb.de> Cc: Tejun Heo <tj@kernel.org> Cc: Nick Desaulniers <ndesaulniers@google.com> Cc: Nathan Chancellor <nathan@kernel.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent 8a28a0b commit afa4bb7

File tree

2 files changed

+16
-12
lines changed

2 files changed

+16
-12
lines changed

include/linux/workqueue.h

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ enum {
6868
WORK_OFFQ_FLAG_BASE = WORK_STRUCT_COLOR_SHIFT,
6969

7070
__WORK_OFFQ_CANCELING = WORK_OFFQ_FLAG_BASE,
71-
WORK_OFFQ_CANCELING = (1 << __WORK_OFFQ_CANCELING),
7271

7372
/*
7473
* When a work item is off queue, its high bits point to the last
@@ -79,12 +78,6 @@ enum {
7978
WORK_OFFQ_POOL_SHIFT = WORK_OFFQ_FLAG_BASE + WORK_OFFQ_FLAG_BITS,
8079
WORK_OFFQ_LEFT = BITS_PER_LONG - WORK_OFFQ_POOL_SHIFT,
8180
WORK_OFFQ_POOL_BITS = WORK_OFFQ_LEFT <= 31 ? WORK_OFFQ_LEFT : 31,
82-
WORK_OFFQ_POOL_NONE = (1LU << WORK_OFFQ_POOL_BITS) - 1,
83-
84-
/* convenience constants */
85-
WORK_STRUCT_FLAG_MASK = (1UL << WORK_STRUCT_FLAG_BITS) - 1,
86-
WORK_STRUCT_WQ_DATA_MASK = ~WORK_STRUCT_FLAG_MASK,
87-
WORK_STRUCT_NO_POOL = (unsigned long)WORK_OFFQ_POOL_NONE << WORK_OFFQ_POOL_SHIFT,
8881

8982
/* bit mask for work_busy() return values */
9083
WORK_BUSY_PENDING = 1 << 0,
@@ -94,6 +87,14 @@ enum {
9487
WORKER_DESC_LEN = 24,
9588
};
9689

90+
/* Convenience constants - of type 'unsigned long', not 'enum'! */
91+
#define WORK_OFFQ_CANCELING (1ul << __WORK_OFFQ_CANCELING)
92+
#define WORK_OFFQ_POOL_NONE ((1ul << WORK_OFFQ_POOL_BITS) - 1)
93+
#define WORK_STRUCT_NO_POOL (WORK_OFFQ_POOL_NONE << WORK_OFFQ_POOL_SHIFT)
94+
95+
#define WORK_STRUCT_FLAG_MASK ((1ul << WORK_STRUCT_FLAG_BITS) - 1)
96+
#define WORK_STRUCT_WQ_DATA_MASK (~WORK_STRUCT_FLAG_MASK)
97+
9798
struct work_struct {
9899
atomic_long_t data;
99100
struct list_head entry;

kernel/workqueue.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -705,12 +705,17 @@ static void clear_work_data(struct work_struct *work)
705705
set_work_data(work, WORK_STRUCT_NO_POOL, 0);
706706
}
707707

708+
static inline struct pool_workqueue *work_struct_pwq(unsigned long data)
709+
{
710+
return (struct pool_workqueue *)(data & WORK_STRUCT_WQ_DATA_MASK);
711+
}
712+
708713
static struct pool_workqueue *get_work_pwq(struct work_struct *work)
709714
{
710715
unsigned long data = atomic_long_read(&work->data);
711716

712717
if (data & WORK_STRUCT_PWQ)
713-
return (void *)(data & WORK_STRUCT_WQ_DATA_MASK);
718+
return work_struct_pwq(data);
714719
else
715720
return NULL;
716721
}
@@ -738,8 +743,7 @@ static struct worker_pool *get_work_pool(struct work_struct *work)
738743
assert_rcu_or_pool_mutex();
739744

740745
if (data & WORK_STRUCT_PWQ)
741-
return ((struct pool_workqueue *)
742-
(data & WORK_STRUCT_WQ_DATA_MASK))->pool;
746+
return work_struct_pwq(data)->pool;
743747

744748
pool_id = data >> WORK_OFFQ_POOL_SHIFT;
745749
if (pool_id == WORK_OFFQ_POOL_NONE)
@@ -760,8 +764,7 @@ static int get_work_pool_id(struct work_struct *work)
760764
unsigned long data = atomic_long_read(&work->data);
761765

762766
if (data & WORK_STRUCT_PWQ)
763-
return ((struct pool_workqueue *)
764-
(data & WORK_STRUCT_WQ_DATA_MASK))->pool->id;
767+
return work_struct_pwq(data)->pool->id;
765768

766769
return data >> WORK_OFFQ_POOL_SHIFT;
767770
}

0 commit comments

Comments
 (0)