Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'ffs-const-v6.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux

Pull ffs const-attribute cleanups from Kees Cook:
"While working on various hardening refactoring a while back we
encountered inconsistencies in the application of __attribute_const__
on the ffs() family of functions.

This series fixes this across all archs and adds KUnit tests.

Notably, this found a theoretical underflow in PCI (also fixed here)
and uncovered an inefficiency in ARC (fixed in the ARC arch PR). I
kept the series separate from the general hardening PR since it is a
stand-alone "topic".

- PCI: Fix theoretical underflow in use of ffs().

- Universally apply __attribute_const__ to all architecture's
ffs()-family of functions.

- Add KUnit tests for ffs() behavior and const-ness"

* tag 'ffs-const-v6.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux:
KUnit: ffs: Validate all the __attribute_const__ annotations
sparc: Add __attribute_const__ to ffs()-family implementations
xtensa: Add __attribute_const__ to ffs()-family implementations
s390: Add __attribute_const__ to ffs()-family implementations
parisc: Add __attribute_const__ to ffs()-family implementations
mips: Add __attribute_const__ to ffs()-family implementations
m68k: Add __attribute_const__ to ffs()-family implementations
openrisc: Add __attribute_const__ to ffs()-family implementations
riscv: Add __attribute_const__ to ffs()-family implementations
hexagon: Add __attribute_const__ to ffs()-family implementations
alpha: Add __attribute_const__ to ffs()-family implementations
sh: Add __attribute_const__ to ffs()-family implementations
powerpc: Add __attribute_const__ to ffs()-family implementations
x86: Add __attribute_const__ to ffs()-family implementations
csky: Add __attribute_const__ to ffs()-family implementations
bitops: Add __attribute_const__ to generic ffs()-family implementations
KUnit: Introduce ffs()-family tests
PCI: Test for bit underflow in pcie_set_readrq()

+661 -76
+7 -7
arch/alpha/include/asm/bitops.h
··· 328 328 return sum; 329 329 } 330 330 331 - static inline unsigned long ffz(unsigned long word) 331 + static inline unsigned long __attribute_const__ ffz(unsigned long word) 332 332 { 333 333 #if defined(CONFIG_ALPHA_EV6) && defined(CONFIG_ALPHA_EV67) 334 334 /* Whee. EV67 can calculate it directly. */ ··· 348 348 /* 349 349 * __ffs = Find First set bit in word. Undefined if no set bit exists. 350 350 */ 351 - static inline unsigned long __ffs(unsigned long word) 351 + static inline __attribute_const__ unsigned long __ffs(unsigned long word) 352 352 { 353 353 #if defined(CONFIG_ALPHA_EV6) && defined(CONFIG_ALPHA_EV67) 354 354 /* Whee. EV67 can calculate it directly. */ ··· 373 373 * differs in spirit from the above __ffs. 374 374 */ 375 375 376 - static inline int ffs(int word) 376 + static inline __attribute_const__ int ffs(int word) 377 377 { 378 378 int result = __ffs(word) + 1; 379 379 return word ? result : 0; ··· 383 383 * fls: find last bit set. 384 384 */ 385 385 #if defined(CONFIG_ALPHA_EV6) && defined(CONFIG_ALPHA_EV67) 386 - static inline int fls64(unsigned long word) 386 + static inline __attribute_const__ int fls64(unsigned long word) 387 387 { 388 388 return 64 - __kernel_ctlz(word); 389 389 } 390 390 #else 391 391 extern const unsigned char __flsm1_tab[256]; 392 392 393 - static inline int fls64(unsigned long x) 393 + static inline __attribute_const__ int fls64(unsigned long x) 394 394 { 395 395 unsigned long t, a, r; 396 396 ··· 403 403 } 404 404 #endif 405 405 406 - static inline unsigned long __fls(unsigned long x) 406 + static inline __attribute_const__ unsigned long __fls(unsigned long x) 407 407 { 408 408 return fls64(x) - 1; 409 409 } 410 410 411 - static inline int fls(unsigned int x) 411 + static inline __attribute_const__ int fls(unsigned int x) 412 412 { 413 413 return fls64(x); 414 414 }
+4 -4
arch/csky/include/asm/bitops.h
··· 9 9 /* 10 10 * asm-generic/bitops/ffs.h 11 11 */ 12 - static inline int ffs(int x) 12 + static inline __attribute_const__ int ffs(int x) 13 13 { 14 14 if (!x) 15 15 return 0; ··· 26 26 /* 27 27 * asm-generic/bitops/__ffs.h 28 28 */ 29 - static __always_inline unsigned long __ffs(unsigned long x) 29 + static __always_inline __attribute_const__ unsigned long __ffs(unsigned long x) 30 30 { 31 31 asm volatile ( 32 32 "brev %0\n" ··· 39 39 /* 40 40 * asm-generic/bitops/fls.h 41 41 */ 42 - static __always_inline int fls(unsigned int x) 42 + static __always_inline __attribute_const__ int fls(unsigned int x) 43 43 { 44 44 asm volatile( 45 45 "ff1 %0\n" ··· 52 52 /* 53 53 * asm-generic/bitops/__fls.h 54 54 */ 55 - static __always_inline unsigned long __fls(unsigned long x) 55 + static __always_inline __attribute_const__ unsigned long __fls(unsigned long x) 56 56 { 57 57 return fls(x) - 1; 58 58 }
+5 -5
arch/hexagon/include/asm/bitops.h
··· 200 200 * 201 201 * Undefined if no zero exists, so code should check against ~0UL first. 202 202 */ 203 - static inline long ffz(int x) 203 + static inline long __attribute_const__ ffz(int x) 204 204 { 205 205 int r; 206 206 ··· 217 217 * This is defined the same way as ffs. 218 218 * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32. 219 219 */ 220 - static inline int fls(unsigned int x) 220 + static inline __attribute_const__ int fls(unsigned int x) 221 221 { 222 222 int r; 223 223 ··· 238 238 * the libc and compiler builtin ffs routines, therefore 239 239 * differs in spirit from the above ffz (man ffs). 240 240 */ 241 - static inline int ffs(int x) 241 + static inline __attribute_const__ int ffs(int x) 242 242 { 243 243 int r; 244 244 ··· 260 260 * bits_per_long assumed to be 32 261 261 * numbering starts at 0 I think (instead of 1 like ffs) 262 262 */ 263 - static inline unsigned long __ffs(unsigned long word) 263 + static inline __attribute_const__ unsigned long __ffs(unsigned long word) 264 264 { 265 265 int num; 266 266 ··· 278 278 * Undefined if no set bit exists, so code should check against 0 first. 279 279 * bits_per_long assumed to be 32 280 280 */ 281 - static inline unsigned long __fls(unsigned long word) 281 + static inline __attribute_const__ unsigned long __fls(unsigned long word) 282 282 { 283 283 int num; 284 284
+7 -7
arch/m68k/include/asm/bitops.h
··· 465 465 * ffz = Find First Zero in word. Undefined if no zero exists, 466 466 * so code should check against ~0UL first.. 467 467 */ 468 - static inline unsigned long ffz(unsigned long word) 468 + static inline unsigned long __attribute_const__ ffz(unsigned long word) 469 469 { 470 470 int res; 471 471 ··· 488 488 */ 489 489 #if (defined(__mcfisaaplus__) || defined(__mcfisac__)) && \ 490 490 !defined(CONFIG_M68000) 491 - static inline unsigned long __ffs(unsigned long x) 491 + static inline __attribute_const__ unsigned long __ffs(unsigned long x) 492 492 { 493 493 __asm__ __volatile__ ("bitrev %0; ff1 %0" 494 494 : "=d" (x) ··· 496 496 return x; 497 497 } 498 498 499 - static inline int ffs(int x) 499 + static inline __attribute_const__ int ffs(int x) 500 500 { 501 501 if (!x) 502 502 return 0; ··· 518 518 * the libc and compiler builtin ffs routines, therefore 519 519 * differs in spirit from the above ffz (man ffs). 520 520 */ 521 - static inline int ffs(int x) 521 + static inline __attribute_const__ int ffs(int x) 522 522 { 523 523 int cnt; 524 524 ··· 528 528 return 32 - cnt; 529 529 } 530 530 531 - static inline unsigned long __ffs(unsigned long x) 531 + static inline __attribute_const__ unsigned long __ffs(unsigned long x) 532 532 { 533 533 return ffs(x) - 1; 534 534 } ··· 536 536 /* 537 537 * fls: find last bit set. 538 538 */ 539 - static inline int fls(unsigned int x) 539 + static inline __attribute_const__ int fls(unsigned int x) 540 540 { 541 541 int cnt; 542 542 ··· 546 546 return 32 - cnt; 547 547 } 548 548 549 - static inline unsigned long __fls(unsigned long x) 549 + static inline __attribute_const__ unsigned long __fls(unsigned long x) 550 550 { 551 551 return fls(x) - 1; 552 552 }
+4 -4
arch/mips/include/asm/bitops.h
··· 327 327 * Return the bit position (0..63) of the most significant 1 bit in a word 328 328 * Returns -1 if no 1 bit exists 329 329 */ 330 - static __always_inline unsigned long __fls(unsigned long word) 330 + static __always_inline __attribute_const__ unsigned long __fls(unsigned long word) 331 331 { 332 332 int num; 333 333 ··· 393 393 * Returns 0..SZLONG-1 394 394 * Undefined if no bit exists, so code should check against 0 first. 395 395 */ 396 - static __always_inline unsigned long __ffs(unsigned long word) 396 + static __always_inline __attribute_const__ unsigned long __ffs(unsigned long word) 397 397 { 398 398 return __fls(word & -word); 399 399 } ··· 405 405 * This is defined the same way as ffs. 406 406 * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32. 407 407 */ 408 - static inline int fls(unsigned int x) 408 + static inline __attribute_const__ int fls(unsigned int x) 409 409 { 410 410 int r; 411 411 ··· 458 458 * the libc and compiler builtin ffs routines, therefore 459 459 * differs in spirit from the below ffz (man ffs). 460 460 */ 461 - static inline int ffs(int word) 461 + static inline __attribute_const__ int ffs(int word) 462 462 { 463 463 if (!word) 464 464 return 0;
+1 -1
arch/openrisc/include/asm/bitops/__ffs.h
··· 11 11 12 12 #ifdef CONFIG_OPENRISC_HAVE_INST_FF1 13 13 14 - static inline unsigned long __ffs(unsigned long x) 14 + static inline __attribute_const__ unsigned long __ffs(unsigned long x) 15 15 { 16 16 int ret; 17 17
+1 -1
arch/openrisc/include/asm/bitops/__fls.h
··· 11 11 12 12 #ifdef CONFIG_OPENRISC_HAVE_INST_FL1 13 13 14 - static inline unsigned long __fls(unsigned long x) 14 + static inline __attribute_const__ unsigned long __fls(unsigned long x) 15 15 { 16 16 int ret; 17 17
+1 -1
arch/openrisc/include/asm/bitops/ffs.h
··· 10 10 11 11 #ifdef CONFIG_OPENRISC_HAVE_INST_FF1 12 12 13 - static inline int ffs(int x) 13 + static inline __attribute_const__ int ffs(int x) 14 14 { 15 15 int ret; 16 16
+1 -1
arch/openrisc/include/asm/bitops/fls.h
··· 11 11 12 12 #ifdef CONFIG_OPENRISC_HAVE_INST_FL1 13 13 14 - static inline int fls(unsigned int x) 14 + static inline __attribute_const__ int fls(unsigned int x) 15 15 { 16 16 int ret; 17 17
+3 -3
arch/parisc/include/asm/bitops.h
··· 123 123 * cycles for each mispredicted branch. 124 124 */ 125 125 126 - static __inline__ unsigned long __ffs(unsigned long x) 126 + static __inline__ __attribute_const__ unsigned long __ffs(unsigned long x) 127 127 { 128 128 unsigned long ret; 129 129 ··· 161 161 * This is defined the same way as the libc and compiler builtin 162 162 * ffs routines, therefore differs in spirit from the above ffz (man ffs). 163 163 */ 164 - static __inline__ int ffs(int x) 164 + static __inline__ __attribute_const__ int ffs(int x) 165 165 { 166 166 return x ? (__ffs((unsigned long)x) + 1) : 0; 167 167 } ··· 171 171 * fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32. 172 172 */ 173 173 174 - static __inline__ int fls(unsigned int x) 174 + static __inline__ __attribute_const__ int fls(unsigned int x) 175 175 { 176 176 int ret; 177 177 if (!x)
+2 -2
arch/powerpc/include/asm/bitops.h
··· 276 276 * fls: find last (most-significant) bit set. 277 277 * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32. 278 278 */ 279 - static __always_inline int fls(unsigned int x) 279 + static __always_inline __attribute_const__ int fls(unsigned int x) 280 280 { 281 281 int lz; 282 282 ··· 294 294 * 32-bit fls calls. 295 295 */ 296 296 #ifdef CONFIG_PPC64 297 - static __always_inline int fls64(__u64 x) 297 + static __always_inline __attribute_const__ int fls64(__u64 x) 298 298 { 299 299 int lz; 300 300
+3 -3
arch/riscv/include/asm/bitops.h
··· 45 45 #error "Unexpected BITS_PER_LONG" 46 46 #endif 47 47 48 - static __always_inline unsigned long variable__ffs(unsigned long word) 48 + static __always_inline __attribute_const__ unsigned long variable__ffs(unsigned long word) 49 49 { 50 50 asm goto(ALTERNATIVE("j %l[legacy]", "nop", 0, 51 51 RISCV_ISA_EXT_ZBB, 1) ··· 74 74 (unsigned long)__builtin_ctzl(word) : \ 75 75 variable__ffs(word)) 76 76 77 - static __always_inline unsigned long variable__fls(unsigned long word) 77 + static __always_inline __attribute_const__ unsigned long variable__fls(unsigned long word) 78 78 { 79 79 asm goto(ALTERNATIVE("j %l[legacy]", "nop", 0, 80 80 RISCV_ISA_EXT_ZBB, 1) ··· 103 103 (unsigned long)(BITS_PER_LONG - 1 - __builtin_clzl(word)) : \ 104 104 variable__fls(word)) 105 105 106 - static __always_inline int variable_ffs(int x) 106 + static __always_inline __attribute_const__ int variable_ffs(int x) 107 107 { 108 108 asm goto(ALTERNATIVE("j %l[legacy]", "nop", 0, 109 109 RISCV_ISA_EXT_ZBB, 1)
+5 -5
arch/s390/include/asm/bitops.h
··· 179 179 * 180 180 * Undefined if no bit exists, so code should check against 0 first. 181 181 */ 182 - static inline unsigned long __ffs(unsigned long word) 182 + static inline __attribute_const__ unsigned long __ffs(unsigned long word) 183 183 { 184 184 return __flogr(-word & word) ^ (BITS_PER_LONG - 1); 185 185 } ··· 191 191 * This is defined the same way as the libc and 192 192 * compiler builtin ffs routines (man ffs). 193 193 */ 194 - static inline int ffs(int word) 194 + static inline __attribute_const__ int ffs(int word) 195 195 { 196 196 unsigned long mask = 2 * BITS_PER_LONG - 1; 197 197 unsigned int val = (unsigned int)word; ··· 205 205 * 206 206 * Undefined if no set bit exists, so code should check against 0 first. 207 207 */ 208 - static inline unsigned long __fls(unsigned long word) 208 + static inline __attribute_const__ unsigned long __fls(unsigned long word) 209 209 { 210 210 return __flogr(word) ^ (BITS_PER_LONG - 1); 211 211 } ··· 221 221 * set bit if value is nonzero. The last (most significant) bit is 222 222 * at position 64. 223 223 */ 224 - static inline int fls64(unsigned long word) 224 + static inline __attribute_const__ int fls64(unsigned long word) 225 225 { 226 226 unsigned long mask = 2 * BITS_PER_LONG - 1; 227 227 ··· 235 235 * This is defined the same way as ffs. 236 236 * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32. 237 237 */ 238 - static inline int fls(unsigned int word) 238 + static inline __attribute_const__ int fls(unsigned int word) 239 239 { 240 240 return fls64(word); 241 241 }
+2 -2
arch/sh/include/asm/bitops.h
··· 24 24 #include <asm-generic/bitops/non-atomic.h> 25 25 #endif 26 26 27 - static inline unsigned long ffz(unsigned long word) 27 + static inline unsigned long __attribute_const__ ffz(unsigned long word) 28 28 { 29 29 unsigned long result; 30 30 ··· 44 44 * 45 45 * Undefined if no bit exists, so code should check against 0 first. 46 46 */ 47 - static inline unsigned long __ffs(unsigned long word) 47 + static inline __attribute_const__ unsigned long __ffs(unsigned long word) 48 48 { 49 49 unsigned long result; 50 50
+4 -4
arch/sparc/include/asm/bitops_64.h
··· 23 23 void clear_bit(unsigned long nr, volatile unsigned long *addr); 24 24 void change_bit(unsigned long nr, volatile unsigned long *addr); 25 25 26 - int fls(unsigned int word); 27 - int __fls(unsigned long word); 26 + int __attribute_const__ fls(unsigned int word); 27 + int __attribute_const__ __fls(unsigned long word); 28 28 29 29 #include <asm-generic/bitops/non-atomic.h> 30 30 ··· 32 32 33 33 #ifdef __KERNEL__ 34 34 35 - int ffs(int x); 36 - unsigned long __ffs(unsigned long); 35 + int __attribute_const__ ffs(int x); 36 + unsigned long __attribute_const__ __ffs(unsigned long); 37 37 38 38 #include <asm-generic/bitops/ffz.h> 39 39 #include <asm-generic/bitops/sched.h>
+6 -6
arch/x86/include/asm/bitops.h
··· 246 246 variable_test_bit(nr, addr); 247 247 } 248 248 249 - static __always_inline unsigned long variable__ffs(unsigned long word) 249 + static __always_inline __attribute_const__ unsigned long variable__ffs(unsigned long word) 250 250 { 251 251 asm("tzcnt %1,%0" 252 252 : "=r" (word) ··· 265 265 (unsigned long)__builtin_ctzl(word) : \ 266 266 variable__ffs(word)) 267 267 268 - static __always_inline unsigned long variable_ffz(unsigned long word) 268 + static __always_inline __attribute_const__ unsigned long variable_ffz(unsigned long word) 269 269 { 270 270 return variable__ffs(~word); 271 271 } ··· 287 287 * 288 288 * Undefined if no set bit exists, so code should check against 0 first. 289 289 */ 290 - static __always_inline unsigned long __fls(unsigned long word) 290 + static __always_inline __attribute_const__ unsigned long __fls(unsigned long word) 291 291 { 292 292 if (__builtin_constant_p(word)) 293 293 return BITS_PER_LONG - 1 - __builtin_clzl(word); ··· 301 301 #undef ADDR 302 302 303 303 #ifdef __KERNEL__ 304 - static __always_inline int variable_ffs(int x) 304 + static __always_inline __attribute_const__ int variable_ffs(int x) 305 305 { 306 306 int r; 307 307 ··· 355 355 * set bit if value is nonzero. The last (most significant) bit is 356 356 * at position 32. 357 357 */ 358 - static __always_inline int fls(unsigned int x) 358 + static __always_inline __attribute_const__ int fls(unsigned int x) 359 359 { 360 360 int r; 361 361 ··· 400 400 * at position 64. 401 401 */ 402 402 #ifdef CONFIG_X86_64 403 - static __always_inline int fls64(__u64 x) 403 + static __always_inline __attribute_const__ int fls64(__u64 x) 404 404 { 405 405 int bitpos = -1; 406 406
+5 -5
arch/xtensa/include/asm/bitops.h
··· 37 37 * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1). 38 38 */ 39 39 40 - static inline int ffz(unsigned long x) 40 + static inline int __attribute_const__ ffz(unsigned long x) 41 41 { 42 42 return 31 - __cntlz(~x & -~x); 43 43 } ··· 46 46 * __ffs: Find first bit set in word. Return 0 for bit 0 47 47 */ 48 48 49 - static inline unsigned long __ffs(unsigned long x) 49 + static inline __attribute_const__ unsigned long __ffs(unsigned long x) 50 50 { 51 51 return 31 - __cntlz(x & -x); 52 52 } ··· 57 57 * differs in spirit from the above ffz (man ffs). 58 58 */ 59 59 60 - static inline int ffs(unsigned long x) 60 + static inline __attribute_const__ int ffs(unsigned long x) 61 61 { 62 62 return 32 - __cntlz(x & -x); 63 63 } ··· 67 67 * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32. 68 68 */ 69 69 70 - static inline int fls (unsigned int x) 70 + static inline __attribute_const__ int fls (unsigned int x) 71 71 { 72 72 return 32 - __cntlz(x); 73 73 } ··· 78 78 * 79 79 * Undefined if no set bit exists, so code should check against 0 first. 80 80 */ 81 - static inline unsigned long __fls(unsigned long word) 81 + static inline __attribute_const__ unsigned long __fls(unsigned long word) 82 82 { 83 83 return 31 - __cntlz(word); 84 84 }
+5 -1
drivers/pci/pci.c
··· 5932 5932 { 5933 5933 u16 v; 5934 5934 int ret; 5935 + unsigned int firstbit; 5935 5936 struct pci_host_bridge *bridge = pci_find_host_bridge(dev->bus); 5936 5937 5937 5938 if (rq < 128 || rq > 4096 || !is_power_of_2(rq)) ··· 5950 5949 rq = mps; 5951 5950 } 5952 5951 5953 - v = FIELD_PREP(PCI_EXP_DEVCTL_READRQ, ffs(rq) - 8); 5952 + firstbit = ffs(rq); 5953 + if (firstbit < 8) 5954 + return -EINVAL; 5955 + v = FIELD_PREP(PCI_EXP_DEVCTL_READRQ, firstbit - 8); 5954 5956 5955 5957 if (bridge->no_inc_mrrs) { 5956 5958 int max_mrrs = pcie_get_readrq(dev);
+1 -1
include/asm-generic/bitops/__ffs.h
··· 10 10 * 11 11 * Undefined if no bit exists, so code should check against 0 first. 12 12 */ 13 - static __always_inline unsigned int generic___ffs(unsigned long word) 13 + static __always_inline __attribute_const__ unsigned int generic___ffs(unsigned long word) 14 14 { 15 15 unsigned int num = 0; 16 16
+1 -1
include/asm-generic/bitops/__fls.h
··· 10 10 * 11 11 * Undefined if no set bit exists, so code should check against 0 first. 12 12 */ 13 - static __always_inline unsigned int generic___fls(unsigned long word) 13 + static __always_inline __attribute_const__ unsigned int generic___fls(unsigned long word) 14 14 { 15 15 unsigned int num = BITS_PER_LONG - 1; 16 16
+1 -1
include/asm-generic/bitops/builtin-__ffs.h
··· 8 8 * 9 9 * Undefined if no bit exists, so code should check against 0 first. 10 10 */ 11 - static __always_inline unsigned int __ffs(unsigned long word) 11 + static __always_inline __attribute_const__ unsigned int __ffs(unsigned long word) 12 12 { 13 13 return __builtin_ctzl(word); 14 14 }
+1 -1
include/asm-generic/bitops/builtin-__fls.h
··· 8 8 * 9 9 * Undefined if no set bit exists, so code should check against 0 first. 10 10 */ 11 - static __always_inline unsigned int __fls(unsigned long word) 11 + static __always_inline __attribute_const__ unsigned int __fls(unsigned long word) 12 12 { 13 13 return (sizeof(word) * 8) - 1 - __builtin_clzl(word); 14 14 }
+1 -1
include/asm-generic/bitops/builtin-fls.h
··· 9 9 * This is defined the same way as ffs. 10 10 * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32. 11 11 */ 12 - static __always_inline int fls(unsigned int x) 12 + static __always_inline __attribute_const__ int fls(unsigned int x) 13 13 { 14 14 return x ? sizeof(x) * 8 - __builtin_clz(x) : 0; 15 15 }
+1 -1
include/asm-generic/bitops/ffs.h
··· 10 10 * the libc and compiler builtin ffs routines, therefore 11 11 * differs in spirit from ffz (man ffs). 12 12 */ 13 - static inline int generic_ffs(int x) 13 + static inline __attribute_const__ int generic_ffs(int x) 14 14 { 15 15 int r = 1; 16 16
+1 -1
include/asm-generic/bitops/fls.h
··· 10 10 * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32. 11 11 */ 12 12 13 - static __always_inline int generic_fls(unsigned int x) 13 + static __always_inline __attribute_const__ int generic_fls(unsigned int x) 14 14 { 15 15 int r = 32; 16 16
+2 -2
include/asm-generic/bitops/fls64.h
··· 16 16 * at position 64. 17 17 */ 18 18 #if BITS_PER_LONG == 32 19 - static __always_inline int fls64(__u64 x) 19 + static __always_inline __attribute_const__ int fls64(__u64 x) 20 20 { 21 21 __u32 h = x >> 32; 22 22 if (h) ··· 24 24 return fls(x); 25 25 } 26 26 #elif BITS_PER_LONG == 64 27 - static __always_inline int fls64(__u64 x) 27 + static __always_inline __attribute_const__ int fls64(__u64 x) 28 28 { 29 29 if (x == 0) 30 30 return 0;
+1 -1
include/linux/bitops.h
··· 267 267 * The result is not defined if no bits are set, so check that @word 268 268 * is non-zero before calling this. 269 269 */ 270 - static inline unsigned int __ffs64(u64 word) 270 + static inline __attribute_const__ unsigned int __ffs64(u64 word) 271 271 { 272 272 #if BITS_PER_LONG == 32 273 273 if (((u32)word) == 0UL)
+14
lib/Kconfig.debug
··· 2479 2479 depends on KUNIT 2480 2480 default KUNIT_ALL_TESTS 2481 2481 2482 + config FFS_KUNIT_TEST 2483 + tristate "KUnit test ffs-family functions at runtime" if !KUNIT_ALL_TESTS 2484 + depends on KUNIT 2485 + default KUNIT_ALL_TESTS 2486 + help 2487 + This builds KUnit tests for ffs-family bit manipulation functions 2488 + including ffs(), __ffs(), fls(), __fls(), fls64(), and __ffs64(). 2489 + 2490 + These tests validate mathematical correctness, edge case handling, 2491 + and cross-architecture consistency of bit scanning functions. 2492 + 2493 + For more information on KUnit and unit tests in general, 2494 + please refer to Documentation/dev-tools/kunit/. 2495 + 2482 2496 config TEST_KSTRTOX 2483 2497 tristate "Test kstrto*() family of functions at runtime" 2484 2498
+4 -4
lib/clz_ctz.c
··· 15 15 #include <linux/kernel.h> 16 16 17 17 int __weak __ctzsi2(int val); 18 - int __weak __ctzsi2(int val) 18 + int __weak __attribute_const__ __ctzsi2(int val) 19 19 { 20 20 return __ffs(val); 21 21 } 22 22 EXPORT_SYMBOL(__ctzsi2); 23 23 24 24 int __weak __clzsi2(int val); 25 - int __weak __clzsi2(int val) 25 + int __weak __attribute_const__ __clzsi2(int val) 26 26 { 27 27 return 32 - fls(val); 28 28 } 29 29 EXPORT_SYMBOL(__clzsi2); 30 30 31 31 int __weak __clzdi2(u64 val); 32 - int __weak __clzdi2(u64 val) 32 + int __weak __attribute_const__ __clzdi2(u64 val) 33 33 { 34 34 return 64 - fls64(val); 35 35 } 36 36 EXPORT_SYMBOL(__clzdi2); 37 37 38 38 int __weak __ctzdi2(u64 val); 39 - int __weak __ctzdi2(u64 val) 39 + int __weak __attribute_const__ __ctzdi2(u64 val) 40 40 { 41 41 return __ffs64(val); 42 42 }
+1
lib/tests/Makefile
··· 10 10 obj-$(CONFIG_CHECKSUM_KUNIT) += checksum_kunit.o 11 11 obj-$(CONFIG_CMDLINE_KUNIT_TEST) += cmdline_kunit.o 12 12 obj-$(CONFIG_CPUMASK_KUNIT_TEST) += cpumask_kunit.o 13 + obj-$(CONFIG_FFS_KUNIT_TEST) += ffs_kunit.o 13 14 CFLAGS_fortify_kunit.o += $(call cc-disable-warning, unsequenced) 14 15 CFLAGS_fortify_kunit.o += $(call cc-disable-warning, stringop-overread) 15 16 CFLAGS_fortify_kunit.o += $(call cc-disable-warning, stringop-truncation)
+566
lib/tests/ffs_kunit.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * KUnit tests for ffs()-family functions 4 + */ 5 + #include <kunit/test.h> 6 + #include <linux/bitops.h> 7 + 8 + /* 9 + * Test data structures 10 + */ 11 + struct ffs_test_case { 12 + unsigned long input; 13 + int expected_ffs; /* ffs() result (1-based) */ 14 + int expected_fls; /* fls() result (1-based) */ 15 + const char *description; 16 + }; 17 + 18 + struct ffs64_test_case { 19 + u64 input; 20 + int expected_fls64; /* fls64() result (1-based) */ 21 + unsigned int expected_ffs64_0based; /* __ffs64() result (0-based) */ 22 + const char *description; 23 + }; 24 + 25 + /* 26 + * Basic edge cases - core functionality validation 27 + */ 28 + static const struct ffs_test_case basic_test_cases[] = { 29 + /* Zero case - special handling */ 30 + {0x00000000, 0, 0, "zero value"}, 31 + 32 + /* Single bit patterns - powers of 2 */ 33 + {0x00000001, 1, 1, "bit 0 set"}, 34 + {0x00000002, 2, 2, "bit 1 set"}, 35 + {0x00000004, 3, 3, "bit 2 set"}, 36 + {0x00000008, 4, 4, "bit 3 set"}, 37 + {0x00000010, 5, 5, "bit 4 set"}, 38 + {0x00000020, 6, 6, "bit 5 set"}, 39 + {0x00000040, 7, 7, "bit 6 set"}, 40 + {0x00000080, 8, 8, "bit 7 set"}, 41 + {0x00000100, 9, 9, "bit 8 set"}, 42 + {0x00008000, 16, 16, "bit 15 set"}, 43 + {0x00010000, 17, 17, "bit 16 set"}, 44 + {0x40000000, 31, 31, "bit 30 set"}, 45 + {0x80000000, 32, 32, "bit 31 set (sign bit)"}, 46 + 47 + /* Maximum values */ 48 + {0xFFFFFFFF, 1, 32, "all bits set"}, 49 + 50 + /* Multiple bit patterns */ 51 + {0x00000003, 1, 2, "bits 0-1 set"}, 52 + {0x00000007, 1, 3, "bits 0-2 set"}, 53 + {0x0000000F, 1, 4, "bits 0-3 set"}, 54 + {0x000000FF, 1, 8, "bits 0-7 set"}, 55 + {0x0000FFFF, 1, 16, "bits 0-15 set"}, 56 + {0x7FFFFFFF, 1, 31, "bits 0-30 set"}, 57 + 58 + /* Sparse patterns */ 59 + {0x00000101, 1, 9, "bits 0,8 set"}, 60 + {0x00001001, 1, 13, "bits 0,12 set"}, 61 + {0x80000001, 1, 32, "bits 0,31 set"}, 62 + {0x40000002, 2, 31, "bits 1,30 set"}, 63 + }; 64 + 65 + /* 66 + * 64-bit test cases 67 + */ 68 + static const struct ffs64_test_case ffs64_test_cases[] = { 69 + /* Zero case */ 70 + {0x0000000000000000ULL, 0, 0, "zero value"}, 71 + 72 + /* Single bit patterns */ 73 + {0x0000000000000001ULL, 1, 0, "bit 0 set"}, 74 + {0x0000000000000002ULL, 2, 1, "bit 1 set"}, 75 + {0x0000000000000004ULL, 3, 2, "bit 2 set"}, 76 + {0x0000000000000008ULL, 4, 3, "bit 3 set"}, 77 + {0x0000000000008000ULL, 16, 15, "bit 15 set"}, 78 + {0x0000000000010000ULL, 17, 16, "bit 16 set"}, 79 + {0x0000000080000000ULL, 32, 31, "bit 31 set"}, 80 + {0x0000000100000000ULL, 33, 32, "bit 32 set"}, 81 + {0x0000000200000000ULL, 34, 33, "bit 33 set"}, 82 + {0x4000000000000000ULL, 63, 62, "bit 62 set"}, 83 + {0x8000000000000000ULL, 64, 63, "bit 63 set (sign bit)"}, 84 + 85 + /* Maximum values */ 86 + {0xFFFFFFFFFFFFFFFFULL, 64, 0, "all bits set"}, 87 + 88 + /* Cross 32-bit boundary patterns */ 89 + {0x00000000FFFFFFFFULL, 32, 0, "lower 32 bits set"}, 90 + {0xFFFFFFFF00000000ULL, 64, 32, "upper 32 bits set"}, 91 + {0x8000000000000001ULL, 64, 0, "bits 0,63 set"}, 92 + {0x4000000000000002ULL, 63, 1, "bits 1,62 set"}, 93 + 94 + /* Mixed patterns */ 95 + {0x00000001FFFFFFFFULL, 33, 0, "bit 32 + lower 32 bits"}, 96 + {0xFFFFFFFF80000000ULL, 64, 31, "upper 32 bits + bit 31"}, 97 + }; 98 + 99 + /* 100 + * Helper function to validate ffs results with detailed error messages 101 + */ 102 + static void validate_ffs_result(struct kunit *test, unsigned long input, 103 + int actual, int expected, const char *func_name, 104 + const char *description) 105 + { 106 + KUNIT_EXPECT_EQ_MSG(test, actual, expected, 107 + "%s(0x%08lx) [%s]: expected %d, got %d", 108 + func_name, input, description, expected, actual); 109 + } 110 + 111 + /* 112 + * Helper function to validate 64-bit ffs results 113 + */ 114 + static void validate_ffs64_result(struct kunit *test, u64 input, 115 + int actual, int expected, const char *func_name, 116 + const char *description) 117 + { 118 + KUNIT_EXPECT_EQ_MSG(test, actual, expected, 119 + "%s(0x%016llx) [%s]: expected %d, got %d", 120 + func_name, input, description, expected, actual); 121 + } 122 + 123 + /* 124 + * Helper function to validate mathematical relationships between functions 125 + */ 126 + static void validate_ffs_relationships(struct kunit *test, unsigned long input) 127 + { 128 + int ffs_result; 129 + int fls_result; 130 + unsigned int ffs_0based; 131 + unsigned int fls_0based; 132 + 133 + if (input == 0) { 134 + /* Special case: zero input */ 135 + KUNIT_EXPECT_EQ(test, ffs(input), 0); 136 + KUNIT_EXPECT_EQ(test, fls(input), 0); 137 + /* __ffs and __fls are undefined for 0, but often return specific values */ 138 + return; 139 + } 140 + 141 + ffs_result = ffs(input); 142 + fls_result = fls(input); 143 + ffs_0based = __ffs(input); 144 + fls_0based = __fls(input); 145 + 146 + /* Relationship: ffs(x) == __ffs(x) + 1 for x != 0 */ 147 + KUNIT_EXPECT_EQ_MSG(test, ffs_result, ffs_0based + 1, 148 + "ffs(0x%08lx) != __ffs(0x%08lx) + 1: %d != %u + 1", 149 + input, input, ffs_result, ffs_0based); 150 + 151 + /* Relationship: fls(x) == __fls(x) + 1 for x != 0 */ 152 + KUNIT_EXPECT_EQ_MSG(test, fls_result, fls_0based + 1, 153 + "fls(0x%08lx) != __fls(0x%08lx) + 1: %d != %u + 1", 154 + input, input, fls_result, fls_0based); 155 + 156 + /* Range validation */ 157 + KUNIT_EXPECT_GE(test, ffs_result, 1); 158 + KUNIT_EXPECT_LE(test, ffs_result, BITS_PER_LONG); 159 + KUNIT_EXPECT_GE(test, fls_result, 1); 160 + KUNIT_EXPECT_LE(test, fls_result, BITS_PER_LONG); 161 + } 162 + 163 + /* 164 + * Helper function to validate 64-bit relationships 165 + */ 166 + static void validate_ffs64_relationships(struct kunit *test, u64 input) 167 + { 168 + int fls64_result; 169 + unsigned int ffs64_0based; 170 + 171 + if (input == 0) { 172 + KUNIT_EXPECT_EQ(test, fls64(input), 0); 173 + return; 174 + } 175 + 176 + fls64_result = fls64(input); 177 + ffs64_0based = __ffs64(input); 178 + 179 + /* Range validation */ 180 + KUNIT_EXPECT_GE(test, fls64_result, 1); 181 + KUNIT_EXPECT_LE(test, fls64_result, 64); 182 + KUNIT_EXPECT_LT(test, ffs64_0based, 64); 183 + 184 + /* 185 + * Relationships with 32-bit functions should hold for small values 186 + * on all architectures. 187 + */ 188 + if (input <= 0xFFFFFFFFULL) { 189 + unsigned long input_32 = (unsigned long)input; 190 + KUNIT_EXPECT_EQ_MSG(test, fls64(input), fls(input_32), 191 + "fls64(0x%llx) != fls(0x%lx): %d != %d", 192 + input, input_32, fls64(input), fls(input_32)); 193 + 194 + if (input != 0) { 195 + KUNIT_EXPECT_EQ_MSG(test, __ffs64(input), __ffs(input_32), 196 + "__ffs64(0x%llx) != __ffs(0x%lx): %lu != %lu", 197 + input, input_32, 198 + (unsigned long)__ffs64(input), 199 + (unsigned long)__ffs(input_32)); 200 + } 201 + } 202 + } 203 + 204 + /* 205 + * Test basic correctness of all ffs-family functions 206 + */ 207 + static void ffs_basic_correctness_test(struct kunit *test) 208 + { 209 + int i; 210 + 211 + for (i = 0; i < ARRAY_SIZE(basic_test_cases); i++) { 212 + const struct ffs_test_case *tc = &basic_test_cases[i]; 213 + 214 + /* Test ffs() */ 215 + validate_ffs_result(test, tc->input, ffs(tc->input), 216 + tc->expected_ffs, "ffs", tc->description); 217 + 218 + /* Test fls() */ 219 + validate_ffs_result(test, tc->input, fls(tc->input), 220 + tc->expected_fls, "fls", tc->description); 221 + 222 + /* Test __ffs() - skip zero case as it's undefined */ 223 + if (tc->input != 0) { 224 + /* Calculate expected __ffs() result: __ffs(x) == ffs(x) - 1 */ 225 + unsigned int expected_ffs_0based = tc->expected_ffs - 1; 226 + validate_ffs_result(test, tc->input, __ffs(tc->input), 227 + expected_ffs_0based, "__ffs", tc->description); 228 + } 229 + 230 + /* Test __fls() - skip zero case as it's undefined */ 231 + if (tc->input != 0) { 232 + /* Calculate expected __fls() result: __fls(x) == fls(x) - 1 */ 233 + unsigned int expected_fls_0based = tc->expected_fls - 1; 234 + validate_ffs_result(test, tc->input, __fls(tc->input), 235 + expected_fls_0based, "__fls", tc->description); 236 + } 237 + } 238 + } 239 + 240 + /* 241 + * Test 64-bit function correctness 242 + */ 243 + static void ffs64_correctness_test(struct kunit *test) 244 + { 245 + int i; 246 + 247 + for (i = 0; i < ARRAY_SIZE(ffs64_test_cases); i++) { 248 + const struct ffs64_test_case *tc = &ffs64_test_cases[i]; 249 + 250 + /* Test fls64() */ 251 + validate_ffs64_result(test, tc->input, fls64(tc->input), 252 + tc->expected_fls64, "fls64", tc->description); 253 + 254 + /* Test __ffs64() - skip zero case as it's undefined */ 255 + if (tc->input != 0) { 256 + validate_ffs64_result(test, tc->input, __ffs64(tc->input), 257 + tc->expected_ffs64_0based, "__ffs64", 258 + tc->description); 259 + } 260 + } 261 + } 262 + 263 + /* 264 + * Test mathematical relationships between functions 265 + */ 266 + static void ffs_mathematical_relationships_test(struct kunit *test) 267 + { 268 + int i; 269 + 270 + /* Test basic cases */ 271 + for (i = 0; i < ARRAY_SIZE(basic_test_cases); i++) { 272 + validate_ffs_relationships(test, basic_test_cases[i].input); 273 + } 274 + 275 + /* Test 64-bit cases */ 276 + for (i = 0; i < ARRAY_SIZE(ffs64_test_cases); i++) { 277 + validate_ffs64_relationships(test, ffs64_test_cases[i].input); 278 + } 279 + } 280 + 281 + /* 282 + * Test edge cases and boundary conditions 283 + */ 284 + static void ffs_edge_cases_test(struct kunit *test) 285 + { 286 + unsigned long test_patterns[] = { 287 + /* Powers of 2 */ 288 + 1UL, 2UL, 4UL, 8UL, 16UL, 32UL, 64UL, 128UL, 289 + 256UL, 512UL, 1024UL, 2048UL, 4096UL, 8192UL, 290 + 291 + /* Powers of 2 minus 1 */ 292 + 1UL, 3UL, 7UL, 15UL, 31UL, 63UL, 127UL, 255UL, 293 + 511UL, 1023UL, 2047UL, 4095UL, 8191UL, 294 + 295 + /* Boundary values */ 296 + 0x7FFFFFFFUL, /* Maximum positive 32-bit */ 297 + 0x80000000UL, /* Minimum negative 32-bit */ 298 + 0xFFFFFFFFUL, /* Maximum 32-bit unsigned */ 299 + }; 300 + int i; 301 + 302 + for (i = 0; i < ARRAY_SIZE(test_patterns); i++) { 303 + validate_ffs_relationships(test, test_patterns[i]); 304 + } 305 + } 306 + 307 + /* 308 + * Test 64-bit edge cases 309 + */ 310 + static void ffs64_edge_cases_test(struct kunit *test) 311 + { 312 + u64 test_patterns_64[] = { 313 + /* 64-bit powers of 2 */ 314 + 0x0000000100000000ULL, /* 2^32 */ 315 + 0x0000000200000000ULL, /* 2^33 */ 316 + 0x0000000400000000ULL, /* 2^34 */ 317 + 0x0000001000000000ULL, /* 2^36 */ 318 + 0x0000010000000000ULL, /* 2^40 */ 319 + 0x0001000000000000ULL, /* 2^48 */ 320 + 0x0100000000000000ULL, /* 2^56 */ 321 + 0x4000000000000000ULL, /* 2^62 */ 322 + 0x8000000000000000ULL, /* 2^63 */ 323 + 324 + /* Cross-boundary patterns */ 325 + 0x00000000FFFFFFFFULL, /* Lower 32 bits */ 326 + 0xFFFFFFFF00000000ULL, /* Upper 32 bits */ 327 + 0x7FFFFFFFFFFFFFFFULL, /* Maximum positive 64-bit */ 328 + 0xFFFFFFFFFFFFFFFFULL, /* Maximum 64-bit unsigned */ 329 + }; 330 + int i; 331 + 332 + for (i = 0; i < ARRAY_SIZE(test_patterns_64); i++) { 333 + validate_ffs64_relationships(test, test_patterns_64[i]); 334 + } 335 + } 336 + 337 + /* 338 + * ffz() test data - Find First Zero bit test cases 339 + */ 340 + struct ffz_test_case { 341 + unsigned long input; 342 + unsigned long expected_ffz; 343 + const char *description; 344 + }; 345 + 346 + static const struct ffz_test_case ffz_test_cases[] = { 347 + /* Zero bits in specific positions */ 348 + {0xFFFFFFFE, 0, "bit 0 is zero"}, /* ...11111110 */ 349 + {0xFFFFFFFD, 1, "bit 1 is zero"}, /* ...11111101 */ 350 + {0xFFFFFFFB, 2, "bit 2 is zero"}, /* ...11111011 */ 351 + {0xFFFFFFF7, 3, "bit 3 is zero"}, /* ...11110111 */ 352 + {0xFFFFFFEF, 4, "bit 4 is zero"}, /* ...11101111 */ 353 + {0xFFFFFFDF, 5, "bit 5 is zero"}, /* ...11011111 */ 354 + {0xFFFFFFBF, 6, "bit 6 is zero"}, /* ...10111111 */ 355 + {0xFFFFFF7F, 7, "bit 7 is zero"}, /* ...01111111 */ 356 + {0xFFFFFEFF, 8, "bit 8 is zero"}, /* Gap in bit 8 */ 357 + {0xFFFF7FFF, 15, "bit 15 is zero"}, /* Gap in bit 15 */ 358 + {0xFFFEFFFF, 16, "bit 16 is zero"}, /* Gap in bit 16 */ 359 + {0xBFFFFFFF, 30, "bit 30 is zero"}, /* Gap in bit 30 */ 360 + {0x7FFFFFFF, 31, "bit 31 is zero"}, /* 01111111... */ 361 + 362 + /* Multiple zero patterns */ 363 + {0xFFFFFFFC, 0, "bits 0-1 are zero"}, /* ...11111100 */ 364 + {0xFFFFFFF8, 0, "bits 0-2 are zero"}, /* ...11111000 */ 365 + {0xFFFFFFF0, 0, "bits 0-3 are zero"}, /* ...11110000 */ 366 + {0xFFFFFF00, 0, "bits 0-7 are zero"}, /* ...00000000 */ 367 + {0xFFFF0000, 0, "bits 0-15 are zero"}, /* Lower 16 bits zero */ 368 + 369 + /* All zeros (special case) */ 370 + {0x00000000, 0, "all bits zero"}, 371 + 372 + /* Complex patterns */ 373 + {0xFFFDFFFF, 17, "bit 17 is zero"}, /* Gap in bit 17 */ 374 + {0xFFF7FFFF, 19, "bit 19 is zero"}, /* Gap in bit 19 */ 375 + {0xF7FFFFFF, 27, "bit 27 is zero"}, /* Gap in bit 27 */ 376 + {0xDFFFFFFF, 29, "bit 29 is zero"}, /* Gap in bit 29 */ 377 + }; 378 + 379 + /* 380 + * Test basic correctness of ffz() function 381 + */ 382 + static void ffz_basic_correctness_test(struct kunit *test) 383 + { 384 + int i; 385 + 386 + for (i = 0; i < ARRAY_SIZE(ffz_test_cases); i++) { 387 + const struct ffz_test_case *tc = &ffz_test_cases[i]; 388 + unsigned long result = ffz(tc->input); 389 + 390 + KUNIT_EXPECT_EQ_MSG(test, result, tc->expected_ffz, 391 + "ffz(0x%08lx) [%s]: expected %lu, got %lu", 392 + tc->input, tc->description, tc->expected_ffz, result); 393 + } 394 + } 395 + 396 + /* 397 + * Test mathematical relationships between ffz() and other functions 398 + */ 399 + static void validate_ffz_relationships(struct kunit *test, unsigned long input) 400 + { 401 + unsigned long ffz_result; 402 + 403 + if (input == 0) { 404 + /* ffz(0) should return 0 (first zero bit is at position 0) */ 405 + KUNIT_EXPECT_EQ(test, ffz(input), 0); 406 + return; 407 + } 408 + 409 + if (input == ~0UL) { 410 + /* ffz(~0) is undefined (no zero bits) - just verify it doesn't crash */ 411 + ffz_result = ffz(input); 412 + /* Implementation-defined behavior, just ensure it completes */ 413 + return; 414 + } 415 + 416 + ffz_result = ffz(input); 417 + 418 + /* Range validation - result should be within valid bit range */ 419 + KUNIT_EXPECT_LT(test, ffz_result, BITS_PER_LONG); 420 + 421 + /* Verify the bit at ffz_result position is actually zero */ 422 + KUNIT_EXPECT_EQ_MSG(test, (input >> ffz_result) & 1, 0, 423 + "ffz(0x%08lx) = %lu, but bit %lu is not zero", 424 + input, ffz_result, ffz_result); 425 + 426 + /* Core relationship: if we set the ffz bit, ffz should find a different bit */ 427 + if (ffz_result < BITS_PER_LONG - 1) { 428 + unsigned long modified = input | (1UL << ffz_result); 429 + if (modified != ~0UL) { /* Skip if all bits would be set */ 430 + unsigned long new_ffz = ffz(modified); 431 + KUNIT_EXPECT_NE_MSG(test, new_ffz, ffz_result, 432 + "ffz(0x%08lx) = %lu, but setting that bit doesn't change ffz result", 433 + input, ffz_result); 434 + } 435 + } 436 + } 437 + 438 + static void ffz_mathematical_relationships_test(struct kunit *test) 439 + { 440 + unsigned long test_patterns[] = { 441 + /* Powers of 2 with one bit clear */ 442 + 0xFFFFFFFE, 0xFFFFFFFD, 0xFFFFFFFB, 0xFFFFFFF7, 443 + 0xFFFFFFEF, 0xFFFFFFDF, 0xFFFFFFBF, 0xFFFFFF7F, 444 + 445 + /* Multiple patterns */ 446 + 0xFFFFFF00, 0xFFFFF000, 0xFFFF0000, 0xFFF00000, 447 + 0x7FFFFFFF, 0x3FFFFFFF, 0x1FFFFFFF, 0x0FFFFFFF, 448 + 449 + /* Complex bit patterns */ 450 + 0xAAAAAAAA, 0x55555555, 0xCCCCCCCC, 0x33333333, 451 + 0xF0F0F0F0, 0x0F0F0F0F, 0xFF00FF00, 0x00FF00FF, 452 + }; 453 + int i; 454 + 455 + /* Test basic test cases */ 456 + for (i = 0; i < ARRAY_SIZE(ffz_test_cases); i++) { 457 + validate_ffz_relationships(test, ffz_test_cases[i].input); 458 + } 459 + 460 + /* Test additional patterns */ 461 + for (i = 0; i < ARRAY_SIZE(test_patterns); i++) { 462 + validate_ffz_relationships(test, test_patterns[i]); 463 + } 464 + } 465 + 466 + /* 467 + * Test edge cases and boundary conditions for ffz() 468 + */ 469 + static void ffz_edge_cases_test(struct kunit *test) 470 + { 471 + unsigned long edge_patterns[] = { 472 + /* Boundary values */ 473 + 0x00000000, /* All zeros */ 474 + 0x80000000, /* Only MSB set */ 475 + 0x00000001, /* Only LSB set */ 476 + 0x7FFFFFFF, /* MSB clear */ 477 + 0xFFFFFFFE, /* LSB clear */ 478 + 479 + /* Powers of 2 complement patterns (one zero bit each) */ 480 + ~(1UL << 0), ~(1UL << 1), ~(1UL << 2), ~(1UL << 3), 481 + ~(1UL << 4), ~(1UL << 8), ~(1UL << 16), ~(1UL << 31), 482 + 483 + /* Walking zero patterns */ 484 + 0xFFFFFFFE, 0xFFFFFFFD, 0xFFFFFFFB, 0xFFFFFFF7, 485 + 0xFFFFFFEF, 0xFFFFFFDF, 0xFFFFFFBF, 0xFFFFFF7F, 486 + 0xFFFFFEFF, 0xFFFFFDFF, 0xFFFFFBFF, 0xFFFFF7FF, 487 + 488 + /* Multiple zeros */ 489 + 0xFFFFFF00, 0xFFFFF000, 0xFFFF0000, 0xFFF00000, 490 + 0xFF000000, 0xF0000000, 0x00000000, 491 + }; 492 + int i; 493 + 494 + for (i = 0; i < ARRAY_SIZE(edge_patterns); i++) { 495 + validate_ffz_relationships(test, edge_patterns[i]); 496 + } 497 + } 498 + 499 + /* 500 + * To have useful build error output, split the tests into separate 501 + * functions so it's clear which are missing __attribute_const__. 502 + */ 503 + #define CREATE_WRAPPER(func) \ 504 + static noinline bool build_test_##func(void) \ 505 + { \ 506 + int init_##func = 32; \ 507 + int result_##func = func(6); \ 508 + \ 509 + /* Does the static initializer vanish after calling func? */ \ 510 + BUILD_BUG_ON(init_##func < 32); \ 511 + \ 512 + /* "Consume" the results so optimizer doesn't drop them. */ \ 513 + barrier_data(&init_##func); \ 514 + barrier_data(&result_##func); \ 515 + \ 516 + return true; \ 517 + } 518 + CREATE_WRAPPER(ffs) 519 + CREATE_WRAPPER(fls) 520 + CREATE_WRAPPER(__ffs) 521 + CREATE_WRAPPER(__fls) 522 + CREATE_WRAPPER(ffz) 523 + #undef CREATE_WRAPPER 524 + 525 + /* 526 + * Make sure that __attribute_const__ has be applied to all the 527 + * functions. This is a regression test for: 528 + * https://github.com/KSPP/linux/issues/364 529 + */ 530 + static void ffs_attribute_const_test(struct kunit *test) 531 + { 532 + KUNIT_EXPECT_TRUE(test, build_test_ffs()); 533 + KUNIT_EXPECT_TRUE(test, build_test_fls()); 534 + KUNIT_EXPECT_TRUE(test, build_test___ffs()); 535 + KUNIT_EXPECT_TRUE(test, build_test___fls()); 536 + KUNIT_EXPECT_TRUE(test, build_test_ffz()); 537 + } 538 + 539 + /* 540 + * KUnit test case definitions 541 + */ 542 + static struct kunit_case ffs_test_cases[] = { 543 + KUNIT_CASE(ffs_basic_correctness_test), 544 + KUNIT_CASE(ffs64_correctness_test), 545 + KUNIT_CASE(ffs_mathematical_relationships_test), 546 + KUNIT_CASE(ffs_edge_cases_test), 547 + KUNIT_CASE(ffs64_edge_cases_test), 548 + KUNIT_CASE(ffz_basic_correctness_test), 549 + KUNIT_CASE(ffz_mathematical_relationships_test), 550 + KUNIT_CASE(ffz_edge_cases_test), 551 + KUNIT_CASE(ffs_attribute_const_test), 552 + {} 553 + }; 554 + 555 + /* 556 + * KUnit test suite definition 557 + */ 558 + static struct kunit_suite ffs_test_suite = { 559 + .name = "ffs", 560 + .test_cases = ffs_test_cases, 561 + }; 562 + 563 + kunit_test_suites(&ffs_test_suite); 564 + 565 + MODULE_DESCRIPTION("KUnit tests for ffs()-family functions"); 566 + MODULE_LICENSE("GPL");