All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] err.h: allow IS_ERR_VALUE to handle properly more types
@ 2016-01-07 14:58 Andrzej Hajda
  2016-01-07 15:48 ` kbuild test robot
  2016-01-15 13:45 ` [PATCH] " Andrzej Hajda
  0 siblings, 2 replies; 26+ messages in thread
From: Andrzej Hajda @ 2016-01-07 14:58 UTC (permalink / raw)
  To: Andrew Morton, open list
  Cc: Andrzej Hajda, Bartlomiej Zolnierkiewicz, Marek Szyprowski

Current implementation of IS_ERR_VALUE works correctly only with
following types:
- unsigned long, unsigned long long,
- short, int, long.
Other types are handled incorrectly either on 32-bit either on 64-bit
either on both architectures.
The patch fixes it by comparing argument with MAX_ERRNO casted
to argument's type for unsigned types and comparing with zero for signed
types. As a result all integer types bigger than char are handled properly.

Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
---
Hi,

I have analyzed usage of IS_ERR_VALUE using coccinelle and in about 35 cases
it is used incorrectly, ie it can hide errors depending of 32/64 bit architecture.
Instead of fixing usage I propose to enhance the macro to cover more types.
And just for record: the macro is used 101 times with signed variables, I am not
sure if it should be preferred over simple comparison "ret < 0", but the new version
can do it as well.

In my previous attempt I have added type checking to the macro, I am not sure which
approach is better[1]. Anyway the previous patch did not catch developers attention.

[1]: http://permalink.gmane.org/gmane.linux.kernel/2111532

And below list of detected potential errors:
drivers/char/mem.c:698:45-46: WARNING: incorrect argument type in IS_ERR_VALUE(( unsigned long long ) offset)
drivers/media/platform/soc_camera/atmel-isi.c:1089:21-22: WARNING: incorrect argument type in IS_ERR_VALUE(irq)
drivers/net/ethernet/freescale/fs_enet/mac-scc.c:149:36-37: WARNING: incorrect argument type in IS_ERR_VALUE(fep -> ring_mem_addr)
drivers/net/ethernet/freescale/ucc_geth.c:2237:48-49: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> tx_bd_ring_offset [ j ])
drivers/net/ethernet/freescale/ucc_geth.c:2314:48-49: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> rx_bd_ring_offset [ j ])
drivers/net/ethernet/freescale/ucc_geth.c:2524:44-45: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> tx_glbl_pram_offset)
drivers/net/ethernet/freescale/ucc_geth.c:2544:45-46: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> thread_dat_tx_offset)
drivers/net/ethernet/freescale/ucc_geth.c:2571:46-47: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> send_q_mem_reg_offset)
drivers/net/ethernet/freescale/ucc_geth.c:2612:42-43: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> scheduler_offset)
drivers/net/ethernet/freescale/ucc_geth.c:2659:54-55: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> tx_fw_statistics_pram_offset)
drivers/net/ethernet/freescale/ucc_geth.c:2696:44-45: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> rx_glbl_pram_offset)
drivers/net/ethernet/freescale/ucc_geth.c:2715:45-46: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> thread_dat_rx_offset)
drivers/net/ethernet/freescale/ucc_geth.c:2736:54-55: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> rx_fw_statistics_pram_offset)
drivers/net/ethernet/freescale/ucc_geth.c:2756:53-54: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> rx_irq_coalescing_tbl_offset)
drivers/net/ethernet/freescale/ucc_geth.c:2822:44-45: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> rx_bd_qs_tbl_offset)
drivers/net/ethernet/freescale/ucc_geth.c:2908:47-48: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> exf_glbl_param_offset)
drivers/net/ethernet/freescale/ucc_geth.c:292:36-37: WARNING: incorrect argument type in IS_ERR_VALUE(init_enet_offset)
drivers/net/ethernet/freescale/ucc_geth.c:3042:39-40: WARNING: incorrect argument type in IS_ERR_VALUE(init_enet_pram_offset)
drivers/soc/fsl/qe/ucc_fast.c:271:60-61: WARNING: incorrect argument type in IS_ERR_VALUE(uccf -> ucc_fast_tx_virtual_fifo_base_offset)
drivers/soc/fsl/qe/ucc_fast.c:284:60-61: WARNING: incorrect argument type in IS_ERR_VALUE(uccf -> ucc_fast_rx_virtual_fifo_base_offset)
drivers/soc/fsl/qe/ucc_slow.c:186:38-39: WARNING: incorrect argument type in IS_ERR_VALUE(uccs -> us_pram_offset)
drivers/soc/fsl/qe/ucc_slow.c:213:38-39: WARNING: incorrect argument type in IS_ERR_VALUE(uccs -> rx_base_offset)
drivers/soc/fsl/qe/ucc_slow.c:224:38-39: WARNING: incorrect argument type in IS_ERR_VALUE(uccs -> tx_base_offset)
drivers/tty/serial/clps711x.c:471:29-30: WARNING: incorrect argument type in IS_ERR_VALUE(s -> port . irq)
drivers/tty/serial/digicolor-usart.c:485:30-31: WARNING: incorrect argument type in IS_ERR_VALUE(dp -> port . irq)
drivers/usb/gadget/udc/fsl_qe_udc.c:2369:26-27: WARNING: incorrect argument type in IS_ERR_VALUE(tmp_addr)
drivers/video/fbdev/exynos/exynos_mipi_dsi.c:406:27-28: WARNING: incorrect argument type in IS_ERR_VALUE(dsim -> irq)
net/ipv4/netfilter/arp_tables.c:1427:39-40: WARNING: incorrect argument type in IS_ERR_VALUE(iter1 -> counters . pcnt)
net/ipv4/netfilter/arp_tables.c:530:34-35: WARNING: incorrect argument type in IS_ERR_VALUE(e -> counters . pcnt)
net/ipv4/netfilter/ip_tables.c:1614:34-35: WARNING: incorrect argument type in IS_ERR_VALUE(e -> counters . pcnt)
net/ipv4/netfilter/ip_tables.c:674:34-35: WARNING: incorrect argument type in IS_ERR_VALUE(e -> counters . pcnt)
net/ipv6/netfilter/ip6_tables.c:1624:34-35: WARNING: incorrect argument type in IS_ERR_VALUE(e -> counters . pcnt)
net/ipv6/netfilter/ip6_tables.c:687:34-35: WARNING: incorrect argument type in IS_ERR_VALUE(e -> counters . pcnt)
drivers/net/ethernet/freescale/fs_enet/mac-fcc.c:110:35-36: WARNING: unknown argument type in IS_ERR_VALUE(fpi -> dpram_offset)

Regards
Andrzej

 include/linux/err.h | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/include/linux/err.h b/include/linux/err.h
index 56762ab..40eca39 100644
--- a/include/linux/err.h
+++ b/include/linux/err.h
@@ -18,7 +18,9 @@
 
 #ifndef __ASSEMBLY__
 
-#define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO)
+#define IS_ERR_VALUE(x) ((typeof(x))(-1) < 0 \
+				? unlikely((x) < 0) \
+				: unlikely((x) >= (typeof(x))-MAX_ERRNO))
 
 static inline void * __must_check ERR_PTR(long error)
 {
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [PATCH] err.h: allow IS_ERR_VALUE to handle properly more types
  2016-01-07 14:58 [PATCH] err.h: allow IS_ERR_VALUE to handle properly more types Andrzej Hajda
@ 2016-01-07 15:48 ` kbuild test robot
  2016-01-28  8:27   ` [PATCH v2] " Andrzej Hajda
  2016-01-15 13:45 ` [PATCH] " Andrzej Hajda
  1 sibling, 1 reply; 26+ messages in thread
From: kbuild test robot @ 2016-01-07 15:48 UTC (permalink / raw)
  To: Andrzej Hajda
  Cc: kbuild-all, Andrew Morton, open list, Andrzej Hajda,
	Bartlomiej Zolnierkiewicz, Marek Szyprowski

[-- Attachment #1: Type: text/plain, Size: 5166 bytes --]

Hi Andrzej,

[auto build test WARNING on v4.4-rc8]
[also build test WARNING on next-20160107]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]

url:    https://github.com/0day-ci/linux/commits/Andrzej-Hajda/err-h-allow-IS_ERR_VALUE-to-handle-properly-more-types/20160107-230216
config: i386-allmodconfig (attached as .config)
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All warnings (new ones prefixed by >>):

   In file included from arch/x86/include/asm/processor.h:31:0,
                    from arch/x86/include/asm/thread_info.h:52,
                    from include/linux/thread_info.h:54,
                    from arch/x86/include/asm/preempt.h:6,
                    from include/linux/preempt.h:59,
                    from include/linux/spinlock.h:50,
                    from drivers/staging/rtl8723au/include/osdep_service.h:22,
                    from drivers/staging/rtl8723au/include/rtl8723a_sreset.h:18,
                    from drivers/staging/rtl8723au/hal/rtl8723a_sreset.c:17:
   include/linux/err.h: In function 'IS_ERR':
>> include/linux/err.h:21:42: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits]
    #define IS_ERR_VALUE(x) ((typeof(x))(-1) < 0 \
                                             ^
>> include/linux/err.h:37:9: note: in expansion of macro 'IS_ERR_VALUE'
     return IS_ERR_VALUE((unsigned long)ptr);
            ^
   In file included from include/linux/linkage.h:4:0,
                    from include/linux/preempt.h:9,
                    from include/linux/spinlock.h:50,
                    from drivers/staging/rtl8723au/include/osdep_service.h:22,
                    from drivers/staging/rtl8723au/include/rtl8723a_sreset.h:18,
                    from drivers/staging/rtl8723au/hal/rtl8723a_sreset.c:17:
   include/linux/err.h:22:20: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits]
        ? unlikely((x) < 0) \
                       ^
   include/linux/compiler.h:166:42: note: in definition of macro 'unlikely'
    # define unlikely(x) __builtin_expect(!!(x), 0)
                                             ^
>> include/linux/err.h:37:9: note: in expansion of macro 'IS_ERR_VALUE'
     return IS_ERR_VALUE((unsigned long)ptr);
            ^
   In file included from arch/x86/include/asm/processor.h:31:0,
                    from arch/x86/include/asm/thread_info.h:52,
                    from include/linux/thread_info.h:54,
                    from arch/x86/include/asm/preempt.h:6,
                    from include/linux/preempt.h:59,
                    from include/linux/spinlock.h:50,
                    from drivers/staging/rtl8723au/include/osdep_service.h:22,
                    from drivers/staging/rtl8723au/include/rtl8723a_sreset.h:18,
                    from drivers/staging/rtl8723au/hal/rtl8723a_sreset.c:17:
   include/linux/err.h: In function 'IS_ERR_OR_NULL':
>> include/linux/err.h:21:42: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits]
    #define IS_ERR_VALUE(x) ((typeof(x))(-1) < 0 \
                                             ^
   include/linux/err.h:42:17: note: in expansion of macro 'IS_ERR_VALUE'
     return !ptr || IS_ERR_VALUE((unsigned long)ptr);
                    ^
   In file included from include/linux/linkage.h:4:0,
                    from include/linux/preempt.h:9,
                    from include/linux/spinlock.h:50,
                    from drivers/staging/rtl8723au/include/osdep_service.h:22,
                    from drivers/staging/rtl8723au/include/rtl8723a_sreset.h:18,
                    from drivers/staging/rtl8723au/hal/rtl8723a_sreset.c:17:
   include/linux/err.h:22:20: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits]
        ? unlikely((x) < 0) \
                       ^
   include/linux/compiler.h:166:42: note: in definition of macro 'unlikely'
    # define unlikely(x) __builtin_expect(!!(x), 0)
                                             ^
   include/linux/err.h:42:17: note: in expansion of macro 'IS_ERR_VALUE'
     return !ptr || IS_ERR_VALUE((unsigned long)ptr);
                    ^

vim +21 include/linux/err.h

    15	 * error and pointer decisions.
    16	 */
    17	#define MAX_ERRNO	4095
    18	
    19	#ifndef __ASSEMBLY__
    20	
  > 21	#define IS_ERR_VALUE(x) ((typeof(x))(-1) < 0 \
    22					? unlikely((x) < 0) \
    23					: unlikely((x) >= (typeof(x))-MAX_ERRNO))
    24	
    25	static inline void * __must_check ERR_PTR(long error)
    26	{
    27		return (void *) error;
    28	}
    29	
    30	static inline long __must_check PTR_ERR(__force const void *ptr)
    31	{
    32		return (long) ptr;
    33	}
    34	
    35	static inline bool __must_check IS_ERR(__force const void *ptr)
    36	{
  > 37		return IS_ERR_VALUE((unsigned long)ptr);
    38	}
    39	
    40	static inline bool __must_check IS_ERR_OR_NULL(__force const void *ptr)

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/octet-stream, Size: 52542 bytes --]

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH] err.h: allow IS_ERR_VALUE to handle properly more types
  2016-01-07 14:58 [PATCH] err.h: allow IS_ERR_VALUE to handle properly more types Andrzej Hajda
  2016-01-07 15:48 ` kbuild test robot
@ 2016-01-15 13:45 ` Andrzej Hajda
  1 sibling, 0 replies; 26+ messages in thread
From: Andrzej Hajda @ 2016-01-15 13:45 UTC (permalink / raw)
  To: Andrew Morton, open list; +Cc: Bartlomiej Zolnierkiewicz, Marek Szyprowski

Hi Andrew,

Have you looked at this patch?
Are there chances to merge it to next?

Two more things I have found:
- current version of IS_ERR_VALUE does not work with unsigned long long
on 32bit arch - commit message should be fixed,
- gcc issues warnings when -Wtype-limits option is enabled, it can be
easily silenced by changing first operator '<' to '<=' in the macro.

Regards
Andrzej

On 01/07/2016 03:58 PM, Andrzej Hajda wrote:
> Current implementation of IS_ERR_VALUE works correctly only with
> following types:
> - unsigned long, unsigned long long,
> - short, int, long.
> Other types are handled incorrectly either on 32-bit either on 64-bit
> either on both architectures.
> The patch fixes it by comparing argument with MAX_ERRNO casted
> to argument's type for unsigned types and comparing with zero for signed
> types. As a result all integer types bigger than char are handled properly.
> 
> Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
> ---
> Hi,
> 
> I have analyzed usage of IS_ERR_VALUE using coccinelle and in about 35 cases
> it is used incorrectly, ie it can hide errors depending of 32/64 bit architecture.
> Instead of fixing usage I propose to enhance the macro to cover more types.
> And just for record: the macro is used 101 times with signed variables, I am not
> sure if it should be preferred over simple comparison "ret < 0", but the new version
> can do it as well.
> 
> In my previous attempt I have added type checking to the macro, I am not sure which
> approach is better[1]. Anyway the previous patch did not catch developers attention.
> 
> [1]: http://permalink.gmane.org/gmane.linux.kernel/2111532
> 
> And below list of detected potential errors:
> drivers/char/mem.c:698:45-46: WARNING: incorrect argument type in IS_ERR_VALUE(( unsigned long long ) offset)
> drivers/media/platform/soc_camera/atmel-isi.c:1089:21-22: WARNING: incorrect argument type in IS_ERR_VALUE(irq)
> drivers/net/ethernet/freescale/fs_enet/mac-scc.c:149:36-37: WARNING: incorrect argument type in IS_ERR_VALUE(fep -> ring_mem_addr)
> drivers/net/ethernet/freescale/ucc_geth.c:2237:48-49: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> tx_bd_ring_offset [ j ])
> drivers/net/ethernet/freescale/ucc_geth.c:2314:48-49: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> rx_bd_ring_offset [ j ])
> drivers/net/ethernet/freescale/ucc_geth.c:2524:44-45: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> tx_glbl_pram_offset)
> drivers/net/ethernet/freescale/ucc_geth.c:2544:45-46: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> thread_dat_tx_offset)
> drivers/net/ethernet/freescale/ucc_geth.c:2571:46-47: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> send_q_mem_reg_offset)
> drivers/net/ethernet/freescale/ucc_geth.c:2612:42-43: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> scheduler_offset)
> drivers/net/ethernet/freescale/ucc_geth.c:2659:54-55: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> tx_fw_statistics_pram_offset)
> drivers/net/ethernet/freescale/ucc_geth.c:2696:44-45: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> rx_glbl_pram_offset)
> drivers/net/ethernet/freescale/ucc_geth.c:2715:45-46: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> thread_dat_rx_offset)
> drivers/net/ethernet/freescale/ucc_geth.c:2736:54-55: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> rx_fw_statistics_pram_offset)
> drivers/net/ethernet/freescale/ucc_geth.c:2756:53-54: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> rx_irq_coalescing_tbl_offset)
> drivers/net/ethernet/freescale/ucc_geth.c:2822:44-45: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> rx_bd_qs_tbl_offset)
> drivers/net/ethernet/freescale/ucc_geth.c:2908:47-48: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> exf_glbl_param_offset)
> drivers/net/ethernet/freescale/ucc_geth.c:292:36-37: WARNING: incorrect argument type in IS_ERR_VALUE(init_enet_offset)
> drivers/net/ethernet/freescale/ucc_geth.c:3042:39-40: WARNING: incorrect argument type in IS_ERR_VALUE(init_enet_pram_offset)
> drivers/soc/fsl/qe/ucc_fast.c:271:60-61: WARNING: incorrect argument type in IS_ERR_VALUE(uccf -> ucc_fast_tx_virtual_fifo_base_offset)
> drivers/soc/fsl/qe/ucc_fast.c:284:60-61: WARNING: incorrect argument type in IS_ERR_VALUE(uccf -> ucc_fast_rx_virtual_fifo_base_offset)
> drivers/soc/fsl/qe/ucc_slow.c:186:38-39: WARNING: incorrect argument type in IS_ERR_VALUE(uccs -> us_pram_offset)
> drivers/soc/fsl/qe/ucc_slow.c:213:38-39: WARNING: incorrect argument type in IS_ERR_VALUE(uccs -> rx_base_offset)
> drivers/soc/fsl/qe/ucc_slow.c:224:38-39: WARNING: incorrect argument type in IS_ERR_VALUE(uccs -> tx_base_offset)
> drivers/tty/serial/clps711x.c:471:29-30: WARNING: incorrect argument type in IS_ERR_VALUE(s -> port . irq)
> drivers/tty/serial/digicolor-usart.c:485:30-31: WARNING: incorrect argument type in IS_ERR_VALUE(dp -> port . irq)
> drivers/usb/gadget/udc/fsl_qe_udc.c:2369:26-27: WARNING: incorrect argument type in IS_ERR_VALUE(tmp_addr)
> drivers/video/fbdev/exynos/exynos_mipi_dsi.c:406:27-28: WARNING: incorrect argument type in IS_ERR_VALUE(dsim -> irq)
> net/ipv4/netfilter/arp_tables.c:1427:39-40: WARNING: incorrect argument type in IS_ERR_VALUE(iter1 -> counters . pcnt)
> net/ipv4/netfilter/arp_tables.c:530:34-35: WARNING: incorrect argument type in IS_ERR_VALUE(e -> counters . pcnt)
> net/ipv4/netfilter/ip_tables.c:1614:34-35: WARNING: incorrect argument type in IS_ERR_VALUE(e -> counters . pcnt)
> net/ipv4/netfilter/ip_tables.c:674:34-35: WARNING: incorrect argument type in IS_ERR_VALUE(e -> counters . pcnt)
> net/ipv6/netfilter/ip6_tables.c:1624:34-35: WARNING: incorrect argument type in IS_ERR_VALUE(e -> counters . pcnt)
> net/ipv6/netfilter/ip6_tables.c:687:34-35: WARNING: incorrect argument type in IS_ERR_VALUE(e -> counters . pcnt)
> drivers/net/ethernet/freescale/fs_enet/mac-fcc.c:110:35-36: WARNING: unknown argument type in IS_ERR_VALUE(fpi -> dpram_offset)
> 
> Regards
> Andrzej
> 
>  include/linux/err.h | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/include/linux/err.h b/include/linux/err.h
> index 56762ab..40eca39 100644
> --- a/include/linux/err.h
> +++ b/include/linux/err.h
> @@ -18,7 +18,9 @@
>  
>  #ifndef __ASSEMBLY__
>  
> -#define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO)
> +#define IS_ERR_VALUE(x) ((typeof(x))(-1) < 0 \
> +				? unlikely((x) < 0) \
> +				: unlikely((x) >= (typeof(x))-MAX_ERRNO))
>  
>  static inline void * __must_check ERR_PTR(long error)
>  {
> 

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH v2] err.h: allow IS_ERR_VALUE to handle properly more types
  2016-01-07 15:48 ` kbuild test robot
@ 2016-01-28  8:27   ` Andrzej Hajda
  2016-02-02  6:23     ` Andrew Morton
  2016-02-03  0:33     ` Andrew Morton
  0 siblings, 2 replies; 26+ messages in thread
From: Andrzej Hajda @ 2016-01-28  8:27 UTC (permalink / raw)
  To: Andrew Morton, open list
  Cc: Andrzej Hajda, Bartlomiej Zolnierkiewicz, Marek Szyprowski

Current implementation of IS_ERR_VALUE works correctly only with
following types:
- unsigned long,
- short, int, long.
Other types are handled incorrectly either on 32-bit either on 64-bit
either on both architectures.
The patch fixes it by comparing argument with MAX_ERRNO casted
to argument's type for unsigned types and comparing with zero for signed
types. As a result all integer types bigger than char are handled properly.

I have analyzed usage of IS_ERR_VALUE using coccinelle and in about 35
cases it is used incorrectly, ie it can hide errors depending of 32/64 bit
architecture. Instead of fixing usage I propose to enhance the macro
to cover more types.
And just for the record: the macro is used 101 times with signed variables,
I am not sure if it should be preferred over simple comparison "ret < 0",
but the new version can do it as well.

And below list of detected potential errors:
drivers/char/mem.c:698:45-46: WARNING: incorrect argument type in IS_ERR_VALUE(( unsigned long long ) offset)
drivers/media/platform/soc_camera/atmel-isi.c:1089:21-22: WARNING: incorrect argument type in IS_ERR_VALUE(irq)
drivers/net/ethernet/freescale/fs_enet/mac-scc.c:149:36-37: WARNING: incorrect argument type in IS_ERR_VALUE(fep -> ring_mem_addr)
drivers/net/ethernet/freescale/ucc_geth.c:2237:48-49: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> tx_bd_ring_offset [ j ])
drivers/net/ethernet/freescale/ucc_geth.c:2314:48-49: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> rx_bd_ring_offset [ j ])
drivers/net/ethernet/freescale/ucc_geth.c:2524:44-45: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> tx_glbl_pram_offset)
drivers/net/ethernet/freescale/ucc_geth.c:2544:45-46: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> thread_dat_tx_offset)
drivers/net/ethernet/freescale/ucc_geth.c:2571:46-47: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> send_q_mem_reg_offset)
drivers/net/ethernet/freescale/ucc_geth.c:2612:42-43: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> scheduler_offset)
drivers/net/ethernet/freescale/ucc_geth.c:2659:54-55: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> tx_fw_statistics_pram_offset)
drivers/net/ethernet/freescale/ucc_geth.c:2696:44-45: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> rx_glbl_pram_offset)
drivers/net/ethernet/freescale/ucc_geth.c:2715:45-46: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> thread_dat_rx_offset)
drivers/net/ethernet/freescale/ucc_geth.c:2736:54-55: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> rx_fw_statistics_pram_offset)
drivers/net/ethernet/freescale/ucc_geth.c:2756:53-54: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> rx_irq_coalescing_tbl_offset)
drivers/net/ethernet/freescale/ucc_geth.c:2822:44-45: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> rx_bd_qs_tbl_offset)
drivers/net/ethernet/freescale/ucc_geth.c:2908:47-48: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> exf_glbl_param_offset)
drivers/net/ethernet/freescale/ucc_geth.c:292:36-37: WARNING: incorrect argument type in IS_ERR_VALUE(init_enet_offset)
drivers/net/ethernet/freescale/ucc_geth.c:3042:39-40: WARNING: incorrect argument type in IS_ERR_VALUE(init_enet_pram_offset)
drivers/soc/fsl/qe/ucc_fast.c:271:60-61: WARNING: incorrect argument type in IS_ERR_VALUE(uccf -> ucc_fast_tx_virtual_fifo_base_offset)
drivers/soc/fsl/qe/ucc_fast.c:284:60-61: WARNING: incorrect argument type in IS_ERR_VALUE(uccf -> ucc_fast_rx_virtual_fifo_base_offset)
drivers/soc/fsl/qe/ucc_slow.c:186:38-39: WARNING: incorrect argument type in IS_ERR_VALUE(uccs -> us_pram_offset)
drivers/soc/fsl/qe/ucc_slow.c:213:38-39: WARNING: incorrect argument type in IS_ERR_VALUE(uccs -> rx_base_offset)
drivers/soc/fsl/qe/ucc_slow.c:224:38-39: WARNING: incorrect argument type in IS_ERR_VALUE(uccs -> tx_base_offset)
drivers/tty/serial/clps711x.c:471:29-30: WARNING: incorrect argument type in IS_ERR_VALUE(s -> port . irq)
drivers/tty/serial/digicolor-usart.c:485:30-31: WARNING: incorrect argument type in IS_ERR_VALUE(dp -> port . irq)
drivers/usb/gadget/udc/fsl_qe_udc.c:2369:26-27: WARNING: incorrect argument type in IS_ERR_VALUE(tmp_addr)
drivers/video/fbdev/exynos/exynos_mipi_dsi.c:406:27-28: WARNING: incorrect argument type in IS_ERR_VALUE(dsim -> irq)
net/ipv4/netfilter/arp_tables.c:1427:39-40: WARNING: incorrect argument type in IS_ERR_VALUE(iter1 -> counters . pcnt)
net/ipv4/netfilter/arp_tables.c:530:34-35: WARNING: incorrect argument type in IS_ERR_VALUE(e -> counters . pcnt)
net/ipv4/netfilter/ip_tables.c:1614:34-35: WARNING: incorrect argument type in IS_ERR_VALUE(e -> counters . pcnt)
net/ipv4/netfilter/ip_tables.c:674:34-35: WARNING: incorrect argument type in IS_ERR_VALUE(e -> counters . pcnt)
net/ipv6/netfilter/ip6_tables.c:1624:34-35: WARNING: incorrect argument type in IS_ERR_VALUE(e -> counters . pcnt)
net/ipv6/netfilter/ip6_tables.c:687:34-35: WARNING: incorrect argument type in IS_ERR_VALUE(e -> counters . pcnt)
drivers/net/ethernet/freescale/fs_enet/mac-fcc.c:110:35-36: WARNING: unknown argument type in IS_ERR_VALUE(fpi -> dpram_offset)

Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
---
v2:
 - use '<= 0' instead of '< 0' to silence gcc verbose warnings,
 - expand commit message.
---
 include/linux/err.h | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/include/linux/err.h b/include/linux/err.h
index 56762ab..43a6adb 100644
--- a/include/linux/err.h
+++ b/include/linux/err.h
@@ -18,7 +18,9 @@
 
 #ifndef __ASSEMBLY__
 
-#define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO)
+#define IS_ERR_VALUE(x) ((typeof(x))(-1) <= 0 \
+				? unlikely((x) < 0) \
+				: unlikely((x) >= (typeof(x))-MAX_ERRNO))
 
 static inline void * __must_check ERR_PTR(long error)
 {
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [PATCH v2] err.h: allow IS_ERR_VALUE to handle properly more types
  2016-01-28  8:27   ` [PATCH v2] " Andrzej Hajda
@ 2016-02-02  6:23     ` Andrew Morton
  2016-02-02  8:22       ` Andrzej Hajda
  2016-02-03  0:33     ` Andrew Morton
  1 sibling, 1 reply; 26+ messages in thread
From: Andrew Morton @ 2016-02-02  6:23 UTC (permalink / raw)
  To: Andrzej Hajda; +Cc: open list, Bartlomiej Zolnierkiewicz, Marek Szyprowski

On Thu, 28 Jan 2016 09:27:28 +0100 Andrzej Hajda <a.hajda@samsung.com> wrote:

> Current implementation of IS_ERR_VALUE works correctly only with
> following types:
> - unsigned long,
> - short, int, long.
> Other types are handled incorrectly either on 32-bit either on 64-bit
> either on both architectures.
> The patch fixes it by comparing argument with MAX_ERRNO casted
> to argument's type for unsigned types and comparing with zero for signed
> types. As a result all integer types bigger than char are handled properly.
> 
> I have analyzed usage of IS_ERR_VALUE using coccinelle and in about 35
> cases it is used incorrectly, ie it can hide errors depending of 32/64 bit
> architecture. Instead of fixing usage I propose to enhance the macro
> to cover more types.
> And just for the record: the macro is used 101 times with signed variables,
> I am not sure if it should be preferred over simple comparison "ret < 0",
> but the new version can do it as well.
> 
> And below list of detected potential errors:
>
> ...
>
> --- a/include/linux/err.h
> +++ b/include/linux/err.h
> @@ -18,7 +18,9 @@
>  
>  #ifndef __ASSEMBLY__
>  
> -#define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO)
> +#define IS_ERR_VALUE(x) ((typeof(x))(-1) <= 0 \
> +				? unlikely((x) < 0) \
> +				: unlikely((x) >= (typeof(x))-MAX_ERRNO))
>  

hm, seems complicated.  Can we simply cast the value to long?

#define IS_ERR_VALUE(x) ((long)x < 0) && (long)x >= (long)-MAX_ERRNO)

and simplify that to

#define IS_ERR_VALUE(x) ((unsigned long)(long)x >= (unsigned long)-MAX_ERRNO)

or something like that.

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v2] err.h: allow IS_ERR_VALUE to handle properly more types
  2016-02-02  6:23     ` Andrew Morton
@ 2016-02-02  8:22       ` Andrzej Hajda
  0 siblings, 0 replies; 26+ messages in thread
From: Andrzej Hajda @ 2016-02-02  8:22 UTC (permalink / raw)
  To: Andrew Morton; +Cc: open list, Bartlomiej Zolnierkiewicz, Marek Szyprowski

On 02/02/2016 07:23 AM, Andrew Morton wrote:
> On Thu, 28 Jan 2016 09:27:28 +0100 Andrzej Hajda <a.hajda@samsung.com> wrote:
>
>> Current implementation of IS_ERR_VALUE works correctly only with
>> following types:
>> - unsigned long,
>> - short, int, long.
>> Other types are handled incorrectly either on 32-bit either on 64-bit
>> either on both architectures.
>> The patch fixes it by comparing argument with MAX_ERRNO casted
>> to argument's type for unsigned types and comparing with zero for signed
>> types. As a result all integer types bigger than char are handled properly.
>>
>> I have analyzed usage of IS_ERR_VALUE using coccinelle and in about 35
>> cases it is used incorrectly, ie it can hide errors depending of 32/64 bit
>> architecture. Instead of fixing usage I propose to enhance the macro
>> to cover more types.
>> And just for the record: the macro is used 101 times with signed variables,
>> I am not sure if it should be preferred over simple comparison "ret < 0",
>> but the new version can do it as well.
>>
>> And below list of detected potential errors:
>>
>> ...
>>
>> --- a/include/linux/err.h
>> +++ b/include/linux/err.h
>> @@ -18,7 +18,9 @@
>>  
>>  #ifndef __ASSEMBLY__
>>  
>> -#define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO)
>> +#define IS_ERR_VALUE(x) ((typeof(x))(-1) <= 0 \
>> +				? unlikely((x) < 0) \
>> +				: unlikely((x) >= (typeof(x))-MAX_ERRNO))
>>  
> hm, seems complicated.  Can we simply cast the value to long?
>
> #define IS_ERR_VALUE(x) ((long)x < 0) && (long)x >= (long)-MAX_ERRNO)
>
> and simplify that to
>
> #define IS_ERR_VALUE(x) ((unsigned long)(long)x >= (unsigned long)-MAX_ERRNO)
>
> or something like that.
It will not work with u32 on 64bit systems.

Short rationales behind my implementation:

1. Typical usage pattern of the macro looks like:
T x;
...
x = -ESOME_ERROR;
...
if (IS_ERR_VALUE(x))
    ...

In error assignment we have casting of -ESOME_ERROR to type T.
Casting of -MAX_ERRNO to the same type in the macro assures that
comparison will be sane, at least for types big enough. In short we ends
at following expression (for unsigned types):
    (T)-ESOME_ERROR >= (T)-MAX_ERRNO
In old implementation we ended at:
    (unsigned)(T)-ESOME_ERROR >= (unsigned)-MAX_ERRNO
Different castings for -ESOME_ERROR and for -MAX_ERRNO makes this
comparison incorrect for some types T.

2. Error checking is completely different for signed and unsigned vars:
a. signed are compared to 0: ret < 0.
b. unsigned are compared with some high value: ret >= (-MAX_ERRNO).
This dualism is clearly visible and emphasized in this implementation.
In old implementation IS_ERR_VALUE works correctly for some signed types
due to obscure C casting rules.

Summarizing: current implementation is short but tricky, answering why
it works/fails for certain types is quite challenging. On the other side
proposed implementation is longer but more straightforward, and of course
is correct for more types :)

Maybe, to make it more clear, it could be good to use separate macro for
signedness:

#define IS_SIGNED_TYPE(t) ((t)(-1) <= 0)

#define IS_ERR_VALUE(x) (IS_SIGNED_TYPE(typeof(x)) \
                ? unlikely((x) < 0) \
                : unlikely((x) >= (typeof(x))-MAX_ERRNO))
 
Regards
Andrzej

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v2] err.h: allow IS_ERR_VALUE to handle properly more types
  2016-01-28  8:27   ` [PATCH v2] " Andrzej Hajda
  2016-02-02  6:23     ` Andrew Morton
@ 2016-02-03  0:33     ` Andrew Morton
  2016-02-03 10:53       ` Andrzej Hajda
  2016-02-03 13:15       ` [PATCH v3] " Andrzej Hajda
  1 sibling, 2 replies; 26+ messages in thread
From: Andrew Morton @ 2016-02-03  0:33 UTC (permalink / raw)
  To: Andrzej Hajda; +Cc: open list, Bartlomiej Zolnierkiewicz, Marek Szyprowski

On Thu, 28 Jan 2016 09:27:28 +0100 Andrzej Hajda <a.hajda@samsung.com> wrote:

>  - use '<= 0' instead of '< 0' to silence gcc verbose warnings,
>  - expand commit message.
> ---
>  include/linux/err.h | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/include/linux/err.h b/include/linux/err.h
> index 56762ab..43a6adb 100644
> --- a/include/linux/err.h
> +++ b/include/linux/err.h
> @@ -18,7 +18,9 @@
>  
>  #ifndef __ASSEMBLY__
>  
> -#define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO)
> +#define IS_ERR_VALUE(x) ((typeof(x))(-1) <= 0 \
> +				? unlikely((x) < 0) \
> +				: unlikely((x) >= (typeof(x))-MAX_ERRNO))

I'm still getting a bunch of 

include/linux/err.h: In function 'IS_ERR':
include/linux/err.h:37: warning: comparison of unsigned expression < 0 is always false
include/linux/err.h: In function 'IS_ERR_OR_NULL':
include/linux/err.h:42: warning: comparison of unsigned expression < 0 is always false

with gcc-4.4.4.

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v2] err.h: allow IS_ERR_VALUE to handle properly more types
  2016-02-03  0:33     ` Andrew Morton
@ 2016-02-03 10:53       ` Andrzej Hajda
  2016-02-03 13:15       ` [PATCH v3] " Andrzej Hajda
  1 sibling, 0 replies; 26+ messages in thread
From: Andrzej Hajda @ 2016-02-03 10:53 UTC (permalink / raw)
  To: Andrew Morton; +Cc: open list, Bartlomiej Zolnierkiewicz, Marek Szyprowski

On 02/03/2016 01:33 AM, Andrew Morton wrote:
> On Thu, 28 Jan 2016 09:27:28 +0100 Andrzej Hajda <a.hajda@samsung.com> wrote:
>
>>  - use '<= 0' instead of '< 0' to silence gcc verbose warnings,
>>  - expand commit message.
>> ---
>>  include/linux/err.h | 4 +++-
>>  1 file changed, 3 insertions(+), 1 deletion(-)
>>
>> diff --git a/include/linux/err.h b/include/linux/err.h
>> index 56762ab..43a6adb 100644
>> --- a/include/linux/err.h
>> +++ b/include/linux/err.h
>> @@ -18,7 +18,9 @@
>>  
>>  #ifndef __ASSEMBLY__
>>  
>> -#define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO)
>> +#define IS_ERR_VALUE(x) ((typeof(x))(-1) <= 0 \
>> +				? unlikely((x) < 0) \
>> +				: unlikely((x) >= (typeof(x))-MAX_ERRNO))
> I'm still getting a bunch of 
>
> include/linux/err.h: In function 'IS_ERR':
> include/linux/err.h:37: warning: comparison of unsigned expression < 0 is always false
> include/linux/err.h: In function 'IS_ERR_OR_NULL':
> include/linux/err.h:42: warning: comparison of unsigned expression < 0 is always false
>
> with gcc-4.4.4.
>
>

These warnings are false positives and gcc up to 4.7 emits them,
gcc 4.8(which I use) behaves correctly (at least on x86 and arm64). I
have tried
to use __builtin_choose_expr instead of ?: operator but it did not help,
although documentation says "the built-in function does not evaluate
the expression that is not chosen"[1].

The sanest gcc silencer I see for now is to replace:
        ? unlikely((x) < 0) \
with
        ? unlikely((x) <= -1) \

On the other side these warnings are caused by -Wtype-limits switch which
is disabled by default in kernel build and treated as broken by Linus [2].
Maybe it is good enough reason to disregard them? :)

Anyway, I will post another iteration.

[1]:
https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#index-g_t_005f_005fbuiltin_005fchoose_005fexpr-4184
[2]: http://permalink.gmane.org/gmane.linux.kernel/2053963

Regards
Andrzej

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH v3] err.h: allow IS_ERR_VALUE to handle properly more types
  2016-02-03  0:33     ` Andrew Morton
  2016-02-03 10:53       ` Andrzej Hajda
@ 2016-02-03 13:15       ` Andrzej Hajda
  2016-02-04 12:40         ` Arnd Bergmann
  2016-02-04 23:37         ` Rasmus Villemoes
  1 sibling, 2 replies; 26+ messages in thread
From: Andrzej Hajda @ 2016-02-03 13:15 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Andrzej Hajda, Bartlomiej Zolnierkiewicz, Marek Szyprowski, open list

Current implementation of IS_ERR_VALUE works correctly only with
following types:
- unsigned long,
- short, int, long.
Other types are handled incorrectly either on 32-bit either on 64-bit
either on both architectures.
The patch fixes it by comparing argument with MAX_ERRNO casted
to argument's type for unsigned types and comparing with zero for signed
types. As a result all integer types bigger than char are handled properly.

I have analyzed usage of IS_ERR_VALUE using coccinelle and in about 35
cases it is used incorrectly, ie it can hide errors depending of 32/64 bit
architecture. Instead of fixing usage I propose to enhance the macro
to cover more types.
And just for the record: the macro is used 101 times with signed variables,
I am not sure if it should be preferred over simple comparison "ret < 0",
but the new version can do it as well.

And below list of detected potential errors:
drivers/char/mem.c:698:45-46: WARNING: incorrect argument type in IS_ERR_VALUE(( unsigned long long ) offset)
drivers/media/platform/soc_camera/atmel-isi.c:1089:21-22: WARNING: incorrect argument type in IS_ERR_VALUE(irq)
drivers/net/ethernet/freescale/fs_enet/mac-scc.c:149:36-37: WARNING: incorrect argument type in IS_ERR_VALUE(fep -> ring_mem_addr)
drivers/net/ethernet/freescale/ucc_geth.c:2237:48-49: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> tx_bd_ring_offset [ j ])
drivers/net/ethernet/freescale/ucc_geth.c:2314:48-49: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> rx_bd_ring_offset [ j ])
drivers/net/ethernet/freescale/ucc_geth.c:2524:44-45: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> tx_glbl_pram_offset)
drivers/net/ethernet/freescale/ucc_geth.c:2544:45-46: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> thread_dat_tx_offset)
drivers/net/ethernet/freescale/ucc_geth.c:2571:46-47: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> send_q_mem_reg_offset)
drivers/net/ethernet/freescale/ucc_geth.c:2612:42-43: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> scheduler_offset)
drivers/net/ethernet/freescale/ucc_geth.c:2659:54-55: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> tx_fw_statistics_pram_offset)
drivers/net/ethernet/freescale/ucc_geth.c:2696:44-45: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> rx_glbl_pram_offset)
drivers/net/ethernet/freescale/ucc_geth.c:2715:45-46: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> thread_dat_rx_offset)
drivers/net/ethernet/freescale/ucc_geth.c:2736:54-55: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> rx_fw_statistics_pram_offset)
drivers/net/ethernet/freescale/ucc_geth.c:2756:53-54: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> rx_irq_coalescing_tbl_offset)
drivers/net/ethernet/freescale/ucc_geth.c:2822:44-45: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> rx_bd_qs_tbl_offset)
drivers/net/ethernet/freescale/ucc_geth.c:2908:47-48: WARNING: incorrect argument type in IS_ERR_VALUE(ugeth -> exf_glbl_param_offset)
drivers/net/ethernet/freescale/ucc_geth.c:292:36-37: WARNING: incorrect argument type in IS_ERR_VALUE(init_enet_offset)
drivers/net/ethernet/freescale/ucc_geth.c:3042:39-40: WARNING: incorrect argument type in IS_ERR_VALUE(init_enet_pram_offset)
drivers/soc/fsl/qe/ucc_fast.c:271:60-61: WARNING: incorrect argument type in IS_ERR_VALUE(uccf -> ucc_fast_tx_virtual_fifo_base_offset)
drivers/soc/fsl/qe/ucc_fast.c:284:60-61: WARNING: incorrect argument type in IS_ERR_VALUE(uccf -> ucc_fast_rx_virtual_fifo_base_offset)
drivers/soc/fsl/qe/ucc_slow.c:186:38-39: WARNING: incorrect argument type in IS_ERR_VALUE(uccs -> us_pram_offset)
drivers/soc/fsl/qe/ucc_slow.c:213:38-39: WARNING: incorrect argument type in IS_ERR_VALUE(uccs -> rx_base_offset)
drivers/soc/fsl/qe/ucc_slow.c:224:38-39: WARNING: incorrect argument type in IS_ERR_VALUE(uccs -> tx_base_offset)
drivers/tty/serial/clps711x.c:471:29-30: WARNING: incorrect argument type in IS_ERR_VALUE(s -> port . irq)
drivers/tty/serial/digicolor-usart.c:485:30-31: WARNING: incorrect argument type in IS_ERR_VALUE(dp -> port . irq)
drivers/usb/gadget/udc/fsl_qe_udc.c:2369:26-27: WARNING: incorrect argument type in IS_ERR_VALUE(tmp_addr)
drivers/video/fbdev/exynos/exynos_mipi_dsi.c:406:27-28: WARNING: incorrect argument type in IS_ERR_VALUE(dsim -> irq)
net/ipv4/netfilter/arp_tables.c:1427:39-40: WARNING: incorrect argument type in IS_ERR_VALUE(iter1 -> counters . pcnt)
net/ipv4/netfilter/arp_tables.c:530:34-35: WARNING: incorrect argument type in IS_ERR_VALUE(e -> counters . pcnt)
net/ipv4/netfilter/ip_tables.c:1614:34-35: WARNING: incorrect argument type in IS_ERR_VALUE(e -> counters . pcnt)
net/ipv4/netfilter/ip_tables.c:674:34-35: WARNING: incorrect argument type in IS_ERR_VALUE(e -> counters . pcnt)
net/ipv6/netfilter/ip6_tables.c:1624:34-35: WARNING: incorrect argument type in IS_ERR_VALUE(e -> counters . pcnt)
net/ipv6/netfilter/ip6_tables.c:687:34-35: WARNING: incorrect argument type in IS_ERR_VALUE(e -> counters . pcnt)
drivers/net/ethernet/freescale/fs_enet/mac-fcc.c:110:35-36: WARNING: unknown argument type in IS_ERR_VALUE(fpi -> dpram_offset)

Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
---
v3:
 - use '<= -1' instead of '< 0' to silence verbose warnings for gcc
   older than 4.8,
v2:
 - use '<= 0' instead of '< 0' to silence gcc verbose warnings,
 - expand commit message.
---
 include/linux/err.h | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/include/linux/err.h b/include/linux/err.h
index 56762ab..b7d4a9f 100644
--- a/include/linux/err.h
+++ b/include/linux/err.h
@@ -18,7 +18,9 @@
 
 #ifndef __ASSEMBLY__
 
-#define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO)
+#define IS_ERR_VALUE(x) ((typeof(x))(-1) <= 0 \
+				? unlikely((x) <= -1) \
+				: unlikely((x) >= (typeof(x))-MAX_ERRNO))
 
 static inline void * __must_check ERR_PTR(long error)
 {
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [PATCH v3] err.h: allow IS_ERR_VALUE to handle properly more types
  2016-02-03 13:15       ` [PATCH v3] " Andrzej Hajda
@ 2016-02-04 12:40         ` Arnd Bergmann
  2016-02-04 14:44           ` Andrzej Hajda
  2016-02-04 18:59           ` Andrew Morton
  2016-02-04 23:37         ` Rasmus Villemoes
  1 sibling, 2 replies; 26+ messages in thread
From: Arnd Bergmann @ 2016-02-04 12:40 UTC (permalink / raw)
  To: Andrzej Hajda
  Cc: Andrew Morton, Bartlomiej Zolnierkiewicz, Marek Szyprowski,
	open list, Bob Peterson

On Wednesday 03 February 2016 14:15:28 Andrzej Hajda wrote:
> diff --git a/include/linux/err.h b/include/linux/err.h
> index 56762ab..b7d4a9f 100644
> --- a/include/linux/err.h
> +++ b/include/linux/err.h
> @@ -18,7 +18,9 @@
>  
>  #ifndef __ASSEMBLY__
>  
> -#define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO)
> +#define IS_ERR_VALUE(x) ((typeof(x))(-1) <= 0 \
> +                               ? unlikely((x) <= -1) \
> +                               : unlikely((x) >= (typeof(x))-MAX_ERRNO))
>  
>  static inline void * __must_check ERR_PTR(long error)
>  {
> 

This has caused a warning to reappear that I had fixed before:

fs/gfs2/dir.c: In function 'get_first_leaf':
fs/gfs2/dir.c:802:9: warning: 'leaf_no' may be used uninitialized in this function [-Wmaybe-uninitialized]
   error = get_leaf(dip, leaf_no, bh_out);
         ^
fs/gfs2/dir.c: In function 'dir_split_leaf':
fs/gfs2/dir.c:1021:8: warning: 'leaf_no' may be used uninitialized in this function [-Wmaybe-uninitialized]
  error = get_leaf(dip, leaf_no, &obh);

See my original patch that was applied at
http://www.gossamer-threads.com/lists/linux/kernel/2353964

Apparently the new version is complex enough to prevent gcc from doing
some optimizations it should do.

I have tried to come up with a new variant that does not bring
the warning back and that should work in all cases:

diff --git a/include/linux/err.h b/include/linux/err.h
index b7d4a9ff6342..bd4936a2c352 100644
--- a/include/linux/err.h
+++ b/include/linux/err.h
@@ -18,9 +18,7 @@
 
 #ifndef __ASSEMBLY__
 
-#define IS_ERR_VALUE(x) ((typeof(x))(-1) <= 0 \
-				? unlikely((x) <= -1) \
-				: unlikely((x) >= (typeof(x))-MAX_ERRNO))
+#define IS_ERR_VALUE(x)	(unlikely((unsigned long long)(x) >= (unsigned long long)(typeof(x))-MAX_ERRNO))
 
 static inline void * __must_check ERR_PTR(long error)
 {


I'm not sure if the cast to 'unsigned long long' might cause less
efficient code to be generated by gcc. I would hope that it is smart
enough to not actually extend shorter variables to 64 bit before
doing the comparison but I have not checked yet.

	Arnd

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [PATCH v3] err.h: allow IS_ERR_VALUE to handle properly more types
  2016-02-04 12:40         ` Arnd Bergmann
@ 2016-02-04 14:44           ` Andrzej Hajda
  2016-02-04 15:00             ` Arnd Bergmann
  2016-02-04 18:59           ` Andrew Morton
  1 sibling, 1 reply; 26+ messages in thread
From: Andrzej Hajda @ 2016-02-04 14:44 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Andrew Morton, Bartlomiej Zolnierkiewicz, Marek Szyprowski,
	open list, Bob Peterson

On 02/04/2016 01:40 PM, Arnd Bergmann wrote:
> On Wednesday 03 February 2016 14:15:28 Andrzej Hajda wrote:
>> diff --git a/include/linux/err.h b/include/linux/err.h
>> index 56762ab..b7d4a9f 100644
>> --- a/include/linux/err.h
>> +++ b/include/linux/err.h
>> @@ -18,7 +18,9 @@
>>  
>>  #ifndef __ASSEMBLY__
>>  
>> -#define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO)
>> +#define IS_ERR_VALUE(x) ((typeof(x))(-1) <= 0 \
>> +                               ? unlikely((x) <= -1) \
>> +                               : unlikely((x) >= (typeof(x))-MAX_ERRNO))
>>  
>>  static inline void * __must_check ERR_PTR(long error)
>>  {
>>
> This has caused a warning to reappear that I had fixed before:
>
> fs/gfs2/dir.c: In function 'get_first_leaf':
> fs/gfs2/dir.c:802:9: warning: 'leaf_no' may be used uninitialized in this function [-Wmaybe-uninitialized]
>    error = get_leaf(dip, leaf_no, bh_out);
>          ^
> fs/gfs2/dir.c: In function 'dir_split_leaf':
> fs/gfs2/dir.c:1021:8: warning: 'leaf_no' may be used uninitialized in this function [-Wmaybe-uninitialized]
>   error = get_leaf(dip, leaf_no, &obh);

What gcc/arch/build options do you use? I cannot reproduce it in my
environment.

Regards
Andrzej

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v3] err.h: allow IS_ERR_VALUE to handle properly more types
  2016-02-04 14:44           ` Andrzej Hajda
@ 2016-02-04 15:00             ` Arnd Bergmann
  2016-02-04 15:10               ` Arnd Bergmann
  0 siblings, 1 reply; 26+ messages in thread
From: Arnd Bergmann @ 2016-02-04 15:00 UTC (permalink / raw)
  To: Andrzej Hajda
  Cc: Andrew Morton, Bartlomiej Zolnierkiewicz, Marek Szyprowski,
	open list, Bob Peterson

On Thursday 04 February 2016 15:44:51 Andrzej Hajda wrote:
> On 02/04/2016 01:40 PM, Arnd Bergmann wrote:
> > On Wednesday 03 February 2016 14:15:28 Andrzej Hajda wrote:
> >> diff --git a/include/linux/err.h b/include/linux/err.h
> >> index 56762ab..b7d4a9f 100644
> >> --- a/include/linux/err.h
> >> +++ b/include/linux/err.h
> >> @@ -18,7 +18,9 @@
> >>  
> >>  #ifndef __ASSEMBLY__
> >>  
> >> -#define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO)
> >> +#define IS_ERR_VALUE(x) ((typeof(x))(-1) <= 0 \
> >> +                               ? unlikely((x) <= -1) \
> >> +                               : unlikely((x) >= (typeof(x))-MAX_ERRNO))
> >>  
> >>  static inline void * __must_check ERR_PTR(long error)
> >>  {
> >>
> > This has caused a warning to reappear that I had fixed before:
> >
> > fs/gfs2/dir.c: In function 'get_first_leaf':
> > fs/gfs2/dir.c:802:9: warning: 'leaf_no' may be used uninitialized in this function [-Wmaybe-uninitialized]
> >    error = get_leaf(dip, leaf_no, bh_out);
> >          ^
> > fs/gfs2/dir.c: In function 'dir_split_leaf':
> > fs/gfs2/dir.c:1021:8: warning: 'leaf_no' may be used uninitialized in this function [-Wmaybe-uninitialized]
> >   error = get_leaf(dip, leaf_no, &obh);
> 
> What gcc/arch/build options do you use? I cannot reproduce it in my
> environment.
> 

I use an ARM gcc-5.3 with an allmodconfig kernel and CONFIG_CC_OPTIMIZE_FOR_SIZE
disabled. I see the same warning with any gcc version since 4.9, but not earlier.

With the IS_ERR_VALUE() macro I sent, I don't see the warning on any gcc
version. I have now also checked that the behavior on x86 gcc-.4.9 is the
same that I see on ARM (I don't have a large collection of x86 gcc versions
though): same warning with linux-next, no warning with my version or after
reverting your patch.

	Arnd

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v3] err.h: allow IS_ERR_VALUE to handle properly more types
  2016-02-04 15:00             ` Arnd Bergmann
@ 2016-02-04 15:10               ` Arnd Bergmann
  0 siblings, 0 replies; 26+ messages in thread
From: Arnd Bergmann @ 2016-02-04 15:10 UTC (permalink / raw)
  To: Andrzej Hajda
  Cc: Andrew Morton, Bartlomiej Zolnierkiewicz, Marek Szyprowski,
	open list, Bob Peterson

On Thursday 04 February 2016 16:00:09 Arnd Bergmann wrote:
> With the IS_ERR_VALUE() macro I sent, I don't see the warning on any gcc
> version. I have now also checked that the behavior on x86 gcc-.4.9 is the
> same that I see on ARM (I don't have a large collection of x86 gcc versions
> though): same warning with linux-next, no warning with my version or after
> reverting your patch.
> 

Sorry, scratch that: I don't get this warning at all on x86 with gcc-4.9,
with any version of err.h.

	Arnd

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v3] err.h: allow IS_ERR_VALUE to handle properly more types
  2016-02-04 12:40         ` Arnd Bergmann
  2016-02-04 14:44           ` Andrzej Hajda
@ 2016-02-04 18:59           ` Andrew Morton
  2016-02-05 10:52             ` Arnd Bergmann
  1 sibling, 1 reply; 26+ messages in thread
From: Andrew Morton @ 2016-02-04 18:59 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Andrzej Hajda, Bartlomiej Zolnierkiewicz, Marek Szyprowski,
	open list, Bob Peterson

On Thu, 04 Feb 2016 13:40:38 +0100 Arnd Bergmann <arnd@arndb.de> wrote:

> diff --git a/include/linux/err.h b/include/linux/err.h
> index b7d4a9ff6342..bd4936a2c352 100644
> --- a/include/linux/err.h
> +++ b/include/linux/err.h
> @@ -18,9 +18,7 @@
>  
>  #ifndef __ASSEMBLY__
>  
> -#define IS_ERR_VALUE(x) ((typeof(x))(-1) <= 0 \
> -				? unlikely((x) <= -1) \
> -				: unlikely((x) >= (typeof(x))-MAX_ERRNO))
> +#define IS_ERR_VALUE(x)	(unlikely((unsigned long long)(x) >= (unsigned long long)(typeof(x))-MAX_ERRNO))
>  
>  static inline void * __must_check ERR_PTR(long error)
>  {
> 
> 
> I'm not sure if the cast to 'unsigned long long' might cause less
> efficient code to be generated by gcc. I would hope that it is smart
> enough to not actually extend shorter variables to 64 bit before
> doing the comparison but I have not checked yet.

I did a quick test with i386 on drivers/nvmem/core.o.  The patch takes
the text size from 9098 bytes to 9133.  That file has 11 instances of
IS_ERR_VALUE().  

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v3] err.h: allow IS_ERR_VALUE to handle properly more types
  2016-02-03 13:15       ` [PATCH v3] " Andrzej Hajda
  2016-02-04 12:40         ` Arnd Bergmann
@ 2016-02-04 23:37         ` Rasmus Villemoes
  2016-02-10 15:16           ` Guenter Roeck
  1 sibling, 1 reply; 26+ messages in thread
From: Rasmus Villemoes @ 2016-02-04 23:37 UTC (permalink / raw)
  To: Andrzej Hajda
  Cc: Andrew Morton, Bartlomiej Zolnierkiewicz, Marek Szyprowski, open list

On Wed, Feb 03 2016, Andrzej Hajda <a.hajda@samsung.com> wrote:

> Current implementation of IS_ERR_VALUE works correctly only with
> following types:
> - unsigned long,
> - short, int, long.
> Other types are handled incorrectly either on 32-bit either on 64-bit
> either on both architectures.
> The patch fixes it by comparing argument with MAX_ERRNO casted
> to argument's type for unsigned types and comparing with zero for signed
> types. As a result all integer types bigger than char are handled properly.
>
>
> Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
> ---
> v3:
>  - use '<= -1' instead of '< 0' to silence verbose warnings for gcc
>    older than 4.8,
> v2:
>  - use '<= 0' instead of '< 0' to silence gcc verbose warnings,
>  - expand commit message.
> ---
>  include/linux/err.h | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/include/linux/err.h b/include/linux/err.h
> index 56762ab..b7d4a9f 100644
> --- a/include/linux/err.h
> +++ b/include/linux/err.h
> @@ -18,7 +18,9 @@
>  
>  #ifndef __ASSEMBLY__
>  
> -#define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO)
> +#define IS_ERR_VALUE(x) ((typeof(x))(-1) <= 0 \
> +				? unlikely((x) <= -1) \
> +				: unlikely((x) >= (typeof(x))-MAX_ERRNO))
>  

I'm a bit worried that you consider any negative value an error when x
is signed - at least that's a change which deserves some comment why
that's ok. For example, I could imagine someone using e.g. INT_MIN as a
sentinel return value meaning 'not an error, but something special
still'.

I think that, since we're there, one should stick in a BUILD_BUG_ON to
catch people passing in a u8 or s8.

Something that seems that it would work for all (wide enough) types
is

({
typeof(x) _x = (x);
BUILD_BUG_ON(sizeof(_x) < 2);
unlikely(_x >= (typeof(x))-MAX_ERRNO &&  _x <= (typeof(x))-1);
})

Whether x is signed or not we want the first condition. If x is unsigned
and at least as wide as int, the -1 in the second condition will be
promoted to the max value typeof(x) can hold, so gcc should trivially
remove the check, and if x is signed, this keeps the previous
semantics. It's also a pattern I expect gcc to be able to optimize
pretty well (that is, if x has type signed int, I expect it'll recognize
that these tests are better done as a single unsigned comparison). Maybe
it'll still give a -Wtype-limit warning for the unsigned case.

If we go with the above, maybe one should also stick in something which
ensures x is not a pointer; (void)(_x+_x); should do it. 

Rasmus

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v3] err.h: allow IS_ERR_VALUE to handle properly more types
  2016-02-04 18:59           ` Andrew Morton
@ 2016-02-05 10:52             ` Arnd Bergmann
  2016-02-08  8:45               ` Andrzej Hajda
  0 siblings, 1 reply; 26+ messages in thread
From: Arnd Bergmann @ 2016-02-05 10:52 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Andrzej Hajda, Bartlomiej Zolnierkiewicz, Marek Szyprowski,
	open list, Bob Peterson

On Thursday 04 February 2016 10:59:31 Andrew Morton wrote:
> On Thu, 04 Feb 2016 13:40:38 +0100 Arnd Bergmann <arnd@arndb.de> wrote:
> 
> > diff --git a/include/linux/err.h b/include/linux/err.h
> > index b7d4a9ff6342..bd4936a2c352 100644
> > --- a/include/linux/err.h
> > +++ b/include/linux/err.h
> > @@ -18,9 +18,7 @@
> >  
> >  #ifndef __ASSEMBLY__
> >  
> > -#define IS_ERR_VALUE(x) ((typeof(x))(-1) <= 0 \
> > -                             ? unlikely((x) <= -1) \
> > -                             : unlikely((x) >= (typeof(x))-MAX_ERRNO))
> > +#define IS_ERR_VALUE(x)      (unlikely((unsigned long long)(x) >= (unsigned long long)(typeof(x))-MAX_ERRNO))
> >  
> >  static inline void * __must_check ERR_PTR(long error)
> >  {
> > 
> > 
> > I'm not sure if the cast to 'unsigned long long' might cause less
> > efficient code to be generated by gcc. I would hope that it is smart
> > enough to not actually extend shorter variables to 64 bit before
> > doing the comparison but I have not checked yet.
> 
> I did a quick test with i386 on drivers/nvmem/core.o.  The patch takes
> the text size from 9098 bytes to 9133.  That file has 11 instances of
> IS_ERR_VALUE().  

This seems to be because it brings back the logic to what it was before
in case of 'int' arguments. I checked the assembly output and found mine
to be identical to v4.4 in this case:

	 text    data     bss     dec     hex filename
v4.4	 9942    1872    2856   14670    394e drivers/nvmem/core.o
a.hajda  9922    1872    2856   14650    393a drivers/nvmem/core.o
arnd	 9942    1872    2856   14670    394e drivers/nvmem/core.o

Andrzej's version is a little shorter on ARM because in case of signed numbers
it only checks for negative values, rather than checking for values in the
[-MAX_ERRNO..-1] range. I think the original behavior is more logical
in this case, and my version restores it.

Looking at drivers/char/mem.o, which had an actual bug that was fixed by
Andrzej's patch, the output with my version and his is identical (failing
an lseek on /dev/mem to offset 0xfffffffffffffe00 or higher, instead of
failing for offset 0x00000000fffffe00-0x00000000ffffffff).

	Arnd

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v3] err.h: allow IS_ERR_VALUE to handle properly more types
  2016-02-05 10:52             ` Arnd Bergmann
@ 2016-02-08  8:45               ` Andrzej Hajda
  2016-02-08 12:01                 ` Arnd Bergmann
  0 siblings, 1 reply; 26+ messages in thread
From: Andrzej Hajda @ 2016-02-08  8:45 UTC (permalink / raw)
  To: Arnd Bergmann, Andrew Morton
  Cc: Bartlomiej Zolnierkiewicz, Marek Szyprowski, open list, Bob Peterson

On 02/05/2016 11:52 AM, Arnd Bergmann wrote:
> On Thursday 04 February 2016 10:59:31 Andrew Morton wrote:
>> On Thu, 04 Feb 2016 13:40:38 +0100 Arnd Bergmann <arnd@arndb.de> wrote:
>>
>>> diff --git a/include/linux/err.h b/include/linux/err.h
>>> index b7d4a9ff6342..bd4936a2c352 100644
>>> --- a/include/linux/err.h
>>> +++ b/include/linux/err.h
>>> @@ -18,9 +18,7 @@
>>>  
>>>  #ifndef __ASSEMBLY__
>>>  
>>> -#define IS_ERR_VALUE(x) ((typeof(x))(-1) <= 0 \
>>> -                             ? unlikely((x) <= -1) \
>>> -                             : unlikely((x) >= (typeof(x))-MAX_ERRNO))
>>> +#define IS_ERR_VALUE(x)      (unlikely((unsigned long long)(x) >= (unsigned long long)(typeof(x))-MAX_ERRNO))
>>>  
>>>  static inline void * __must_check ERR_PTR(long error)
>>>  {
>>>
>>>
>>> I'm not sure if the cast to 'unsigned long long' might cause less
>>> efficient code to be generated by gcc. I would hope that it is smart
>>> enough to not actually extend shorter variables to 64 bit before
>>> doing the comparison but I have not checked yet.
>> I did a quick test with i386 on drivers/nvmem/core.o.  The patch takes
>> the text size from 9098 bytes to 9133.  That file has 11 instances of
>> IS_ERR_VALUE().  
> This seems to be because it brings back the logic to what it was before
> in case of 'int' arguments. I checked the assembly output and found mine
> to be identical to v4.4 in this case:
>
> 	 text    data     bss     dec     hex filename
> v4.4	 9942    1872    2856   14670    394e drivers/nvmem/core.o
> a.hajda  9922    1872    2856   14650    393a drivers/nvmem/core.o
> arnd	 9942    1872    2856   14670    394e drivers/nvmem/core.o

I have compared all proposed version with all compilers I have:

            text       data        bss        dec        hex    filename
gcc-4.4
old         8188       1016       2968      12172       2f8c   
.x86/drivers/nvmem/core.o
andrzej     8155       1016       2968      12139       2f6b   
.x86/drivers/nvmem/core.o
arnd        8188       1016       2968      12172       2f8c   
.x86/drivers/nvmem/core.o
rasmus      8266       1016       2968      12250       2fda   
.x86/drivers/nvmem/core.o
 ---
gcc-4.7
old         7642       3816       3248      14706       3972   
.x86/drivers/nvmem/core.o
andrzej     7606       3816       3248      14670       394e   
.x86/drivers/nvmem/core.o
arnd        7642       3816       3248      14706       3972   
.x86/drivers/nvmem/core.o
rasmus      7719       3816       3248      14783       39bf   
.x86/drivers/nvmem/core.o
 ---
gcc-4.8
old         7735       3888       3272      14895       3a2f   
.x86/drivers/nvmem/core.o
andrzej     7698       3888       3272      14858       3a0a   
.x86/drivers/nvmem/core.o
arnd        7735       3888       3272      14895       3a2f   
.x86/drivers/nvmem/core.o
rasmus      7812       3888       3272      14972       3a7c   
.x86/drivers/nvmem/core.o
 ---
arm-linux-gnueabi-gcc-4.7
old        12776       1680       3432      17888       45e0   
.arm/drivers/nvmem/core.o
andrzej    12772       1680       3432      17884       45dc   
.arm/drivers/nvmem/core.o
arnd       12776       1680       3432      17888       45e0   
.arm/drivers/nvmem/core.o
rasmus     12948       1680       3432      18060       468c   
.arm/drivers/nvmem/core.o
 ---
aarch64-linux-gnu-gcc-4.8
old         5967        440         48       6455       1937   
.arm64/drivers/nvmem/core.o
andrzej     5947        440         48       6435       1923   
.arm64/drivers/nvmem/core.o
arnd        5967        440         48       6455       1937   
.arm64/drivers/nvmem/core.o
rasmus      5991        440         48       6479       194f   
.arm64/drivers/nvmem/core.o
 ---

My version produces shortest code, Arnd's is the same as the old one.
On the other side Rasmus proposition seems to be the most straightforward
to me. Anyway I am not sure if the code length is the most important here.

By the way .data segment size grows almost 4 times between gcc 4.4 and
4.8 :)
Also numbers for arm64 looks interesting.

Just for the record below all proposed implementations:
#define IS_ERR_VALUE_old(x) unlikely((x) >= (unsigned long)-MAX_ERRNO)
#define IS_ERR_VALUE_andrzej(x) ((typeof(x))(-1) <= 0 \
                                ? unlikely((x) <= -1) \
                                : unlikely((x) >= (typeof(x))-MAX_ERRNO))
#define IS_ERR_VALUE_arnd(x)      (unlikely((unsigned long long)(x) >=
(unsigned long long)(typeof(x))-MAX_ERRNO))
#define IS_ERR_VALUE_rasmus(x) ({\
        typeof(x) _x = (x);\
        unlikely(_x >= (typeof(x))-MAX_ERRNO &&  _x <= (typeof(x))-1);\
})

>
> Andrzej's version is a little shorter on ARM because in case of signed numbers
> it only checks for negative values, rather than checking for values in the
> [-MAX_ERRNO..-1] range. I think the original behavior is more logical
> in this case, and my version restores it.

As I looked at the usage of the macro in the kernel I have not found any
code
which could benefit from the original behavior, except some buggy code in
staging which have already pending fix[1].
But maybe it would be better to use IS_ERR_VALUE to always check if err
is in
range [-MAX_ERRNO..-1] and just use simple 'err < 0' in typical case of
signed
types.

[1]: http://permalink.gmane.org/gmane.comp.file-systems.lustre.devel/4164

Regards
Andrzej

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v3] err.h: allow IS_ERR_VALUE to handle properly more types
  2016-02-08  8:45               ` Andrzej Hajda
@ 2016-02-08 12:01                 ` Arnd Bergmann
  2016-02-09  1:44                   ` Al Viro
  2016-02-09  8:42                   ` Andrzej Hajda
  0 siblings, 2 replies; 26+ messages in thread
From: Arnd Bergmann @ 2016-02-08 12:01 UTC (permalink / raw)
  To: Andrzej Hajda
  Cc: Andrew Morton, Bartlomiej Zolnierkiewicz, Marek Szyprowski,
	open list, Bob Peterson

On Monday 08 February 2016 09:45:55 Andrzej Hajda wrote:
> On 02/05/2016 11:52 AM, Arnd Bergmann wrote:
> > On Thursday 04 February 2016 10:59:31 Andrew Morton wrote:

> My version produces shortest code, Arnd's is the same as the old one.
> On the other side Rasmus proposition seems to be the most straightforward
> to me. Anyway I am not sure if the code length is the most important here.
> 
> By the way .data segment size grows almost 4 times between gcc 4.4 and
> 4.8 :)
> Also numbers for arm64 looks interesting.
> 
> Just for the record below all proposed implementations:
> #define IS_ERR_VALUE_old(x) unlikely((x) >= (unsigned long)-MAX_ERRNO)
> #define IS_ERR_VALUE_andrzej(x) ((typeof(x))(-1) <= 0 \
>                                 ? unlikely((x) <= -1) \
>                                 : unlikely((x) >= (typeof(x))-MAX_ERRNO))
> #define IS_ERR_VALUE_arnd(x)      (unlikely((unsigned long long)(x) >=
> (unsigned long long)(typeof(x))-MAX_ERRNO))
> #define IS_ERR_VALUE_rasmus(x) ({\
>         typeof(x) _x = (x);\
>         unlikely(_x >= (typeof(x))-MAX_ERRNO &&  _x <= (typeof(x))-1);\
> })
> 
> >
> > Andrzej's version is a little shorter on ARM because in case of signed numbers
> > it only checks for negative values, rather than checking for values in the
> > [-MAX_ERRNO..-1] range. I think the original behavior is more logical
> > in this case, and my version restores it.
> 
> As I looked at the usage of the macro in the kernel I have not found any
> code
> which could benefit from the original behavior, except some buggy code in
> staging which have already pending fix[1].
> But maybe it would be better to use IS_ERR_VALUE to always check if err
> is in
> range [-MAX_ERRNO..-1] and just use simple 'err < 0' in typical case of
> signed types.

If we do that, should we also make it illegal to use an invalid type
for IS_ERR()? At least that could also catch any use of 'char' and 'unsigned
char' that are still broken.

diff --git a/include/linux/err.h b/include/linux/err.h
index 039b80bb56ae..6700ad40f73f 100644
--- a/include/linux/err.h
+++ b/include/linux/err.h
@@ -18,7 +18,7 @@
 
 #ifndef __ASSEMBLY__
 
-#define IS_ERR_VALUE(x) (unlikely((unsigned long long)(x) >= (unsigned long long)(typeof(x))-MAX_ERRNO))
+#define IS_ERR_VALUE(x) ({typeof(x) max_errno = -MAX_ERRNO; compiletime_assert(max_errno > 0, "IS_ERR_VALUE takes an unsigned argument"); (x >= max_errno); })
 
 static inline void * __must_check ERR_PTR(long error)
 {


Unfortunately, we get a significant number of errors if we do that, I guess the
list is what you had before

	Arnd

/git/arm-soc/drivers/irqchip/irq-hip04.c: In function 'hip04_of_init':                                   
/git/arm-soc/drivers/irqchip/irq-hip04.c:405:203: error: call to '__compiletime_assert_405' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
make[3]: *** [drivers/irqchip/irq-hip04.o] Error 1
/git/arm-soc/drivers/irqchip/irq-gic.c: In function '__gic_init_bases':
/git/arm-soc/drivers/irqchip/irq-gic.c:1106:205: error: call to '__compiletime_assert_1106' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
make[3]: *** [drivers/irqchip/irq-gic.o] Error 1
make[3]: Target `__build' not remade because of errors.
make[2]: *** [drivers/irqchip] Error 2
/git/arm-soc/kernel/pid.c: In function 'alloc_pid':
/git/arm-soc/kernel/pid.c:314:198: error: call to '__compiletime_assert_314' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
/git/arm-soc/kernel/pid.c:314:198: error: call to '__compiletime_assert_314' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
make[3]: *** [kernel/pid.o] Error 1
In function 'arm_smmu_init_domain_context',
    inlined from 'arm_smmu_attach_dev' at /git/arm-soc/drivers/iommu/arm-smmu.c:1138:6:
/git/arm-soc/drivers/iommu/arm-smmu.c:877:198: error: call to '__compiletime_assert_877' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
/git/arm-soc/drivers/iommu/arm-smmu.c:916:198: error: call to '__compiletime_assert_916' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
/git/arm-soc/drivers/iommu/arm-smmu.c: In function 'arm_smmu_attach_dev':
/git/arm-soc/drivers/iommu/arm-smmu.c:1139:199: error: call to '__compiletime_assert_1139' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
make[3]: *** [drivers/iommu/arm-smmu.o] Error 1
/git/arm-soc/drivers/dma/sun4i-dma.c: In function 'generate_ndma_promise':
/git/arm-soc/drivers/dma/sun4i-dma.c:464:198: error: call to '__compiletime_assert_464' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
/git/arm-soc/drivers/dma/sun4i-dma.c: In function 'generate_ddma_promise':
/git/arm-soc/drivers/dma/sun4i-dma.c:521:198: error: call to '__compiletime_assert_521' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
make[3]: *** [drivers/dma/sun4i-dma.o] Error 1
make[3]: Target `__build' not remade because of errors.
make[2]: *** [drivers/iommu] Error 2
In function 'pl011_probe_dt_alias',
    inlined from 'pl011_setup_port' at /git/arm-soc/drivers/tty/serial/amba-pl011.c:2414:8:
/git/arm-soc/drivers/tty/serial/amba-pl011.c:2360:199: error: call to '__compiletime_assert_2360' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
make[4]: *** [drivers/tty/serial/amba-pl011.o] Error 1
/git/arm-soc/drivers/tty/serial/clps711x.c: In function 'uart_clps711x_probe':
/git/arm-soc/drivers/tty/serial/clps711x.c:475:204: error: call to '__compiletime_assert_475' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
make[4]: *** [drivers/tty/serial/clps711x.o] Error 1
/git/arm-soc/drivers/tty/serial/8250/8250_ingenic.c:337:252: error: data definition has no type or storage class [-Werror]
/git/arm-soc/drivers/tty/serial/8250/8250_ingenic.c:337:252: error: type defaults to 'int' in declaration of 'device_initcall' [-Werror=implicit-int]
/git/arm-soc/drivers/tty/serial/8250/8250_ingenic.c:337:1: error: parameter names (without types) in function declaration [-Werror]
 builtin_platform_driver(ingenic_uart_platform_driver);
 ^
/git/arm-soc/drivers/tty/serial/8250/8250_ingenic.c:337:122: error: 'ingenic_uart_platform_driver_init' defined but not used [-Werror=unused-function]
cc1: all warnings being treated as errors
make[5]: *** [drivers/tty/serial/8250/8250_ingenic.o] Error 1
make[5]: Target `__build' not remade because of errors.
make[4]: *** [drivers/tty/serial/8250] Error 2
make[3]: Target `__build' not remade because of errors.
make[2]: *** [drivers/dma] Error 2
/git/arm-soc/drivers/mfd/twl4030-irq.c: In function 'twl4030_init_irq':
/git/arm-soc/drivers/mfd/twl4030-irq.c:699:203: error: call to '__compiletime_assert_699' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
make[3]: *** [drivers/mfd/twl4030-irq.o] Error 1
make[4]: Target `__build' not remade because of errors.
make[3]: *** [drivers/tty/serial] Error 2
/git/arm-soc/fs/afs/write.c: In function 'afs_file_write':
/git/arm-soc/fs/afs/write.c:646:201: error: call to '__compiletime_assert_646' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
make[4]: *** [fs/afs/write.o] Error 1
make[4]: Target `__build' not remade because of errors.
make[3]: *** [fs/afs] Error 2
In function 'da8xx_fb_config_clk_divider',
    inlined from 'da8xx_fb_calc_config_clk_divider' at /git/arm-soc/drivers/video/fbdev/da8xx-fb.c:769:9:
/git/arm-soc/drivers/video/fbdev/da8xx-fb.c:717:199: error: call to '__compiletime_assert_717' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
In function 'lcd_init',
    inlined from 'da8xxfb_set_par' at /git/arm-soc/drivers/video/fbdev/da8xx-fb.c:1284:6:
/git/arm-soc/drivers/video/fbdev/da8xx-fb.c:788:198: error: call to '__compiletime_assert_788' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
make[4]: *** [drivers/video/fbdev/da8xx-fb.o] Error 1
make[3]: Target `__build' not remade because of errors.
make[2]: *** [drivers/tty] Error 2
make[4]: Target `__build' not remade because of errors.
make[3]: *** [drivers/video/fbdev] Error 2
make[3]: Target `__build' not remade because of errors.
make[2]: *** [drivers/video] Error 2
/git/arm-soc/drivers/cpufreq/omap-cpufreq.c: In function 'omap_target':
/git/arm-soc/drivers/cpufreq/omap-cpufreq.c:54:197: error: call to '__compiletime_assert_54' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
make[3]: *** [drivers/cpufreq/omap-cpufreq.o] Error 1
In function 'mmc_select_hs200',
    inlined from 'mmc_select_timing' at /git/arm-soc/drivers/mmc/core/mmc.c:1310:7,
    inlined from 'mmc_init_card' at /git/arm-soc/drivers/mmc/core/mmc.c:1565:6:
/git/arm-soc/drivers/mmc/core/mmc.c:1271:200: error: call to '__compiletime_assert_1271' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
/git/arm-soc/drivers/mmc/core/mmc.c: In function 'mmc_init_card':
/git/arm-soc/drivers/mmc/core/mmc.c:1580:201: error: call to '__compiletime_assert_1580' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
make[4]: *** [drivers/mmc/core/mmc.o] Error 1
make[3]: Target `__build' not remade because of errors.
make[2]: *** [drivers/cpufreq] Error 2
/git/arm-soc/drivers/crypto/caam/ctrl.c: In function 'caam_get_era':
/git/arm-soc/drivers/crypto/caam/ctrl.c:405:201: error: call to '__compiletime_assert_405' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
make[4]: *** [drivers/crypto/caam/ctrl.o] Error 1
make[4]: Target `__build' not remade because of errors.
make[3]: *** [drivers/mmc/core] Error 2
make[4]: Target `__build' not remade because of errors.
make[3]: *** [drivers/crypto/caam] Error 2
In file included from /git/arm-soc/include/linux/clk.h:15:0,
                 from /git/arm-soc/drivers/crypto/ux500/cryp/cryp_core.c:12:
/git/arm-soc/include/linux/err.h: In function 'IS_ERR':
/git/arm-soc/include/linux/err.h:35:215: error: call to '__compiletime_assert_35' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
make[5]: *** [drivers/crypto/ux500/cryp/cryp_core.o] Error 1
make[5]: Target `__build' not remade because of errors.
make[4]: *** [drivers/crypto/ux500/cryp] Error 2
/git/arm-soc/drivers/mmc/host/sdhci.c: In function 'sdhci_do_get_cd':
/git/arm-soc/drivers/mmc/host/sdhci.c:1628:204: error: call to '__compiletime_assert_1628' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
/git/arm-soc/drivers/mmc/host/sdhci.c: In function 'sdhci_add_host':
/git/arm-soc/drivers/mmc/host/sdhci.c:3117:222: error: call to '__compiletime_assert_3117' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
make[4]: *** [drivers/mmc/host/sdhci.o] Error 1
In file included from /git/arm-soc/include/linux/clk.h:15:0,
                 from /git/arm-soc/drivers/crypto/ux500/hash/hash_core.c:16:
/git/arm-soc/include/linux/err.h: In function 'IS_ERR':
/git/arm-soc/include/linux/err.h:35:215: error: call to '__compiletime_assert_35' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
make[5]: *** [drivers/crypto/ux500/hash/hash_core.o] Error 1
make[5]: Target `__build' not remade because of errors.
make[4]: *** [drivers/crypto/ux500/hash] Error 2
make[4]: Target `__build' not remade because of errors.
make[3]: *** [drivers/crypto/ux500] Error 2
make[3]: Target `__build' not remade because of errors.
make[2]: *** [drivers/crypto] Error 2
In file included from /git/arm-soc/drivers/gpu/host1x/hw/host1x01.c:27:0:
/git/arm-soc/drivers/gpu/host1x/hw/intr_hw.c: In function '_host1x_intr_init_host_sync':
/git/arm-soc/drivers/gpu/host1x/hw/intr_hw.c:88:197: error: call to '__compiletime_assert_88' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
make[4]: *** [drivers/gpu/host1x/hw/host1x01.o] Error 1
In file included from /git/arm-soc/drivers/gpu/host1x/hw/host1x02.c:27:0:
/git/arm-soc/drivers/gpu/host1x/hw/intr_hw.c: In function '_host1x_intr_init_host_sync':
/git/arm-soc/drivers/gpu/host1x/hw/intr_hw.c:88:197: error: call to '__compiletime_assert_88' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
make[4]: *** [drivers/gpu/host1x/hw/host1x02.o] Error 1
In file included from /git/arm-soc/drivers/gpu/host1x/hw/host1x04.c:27:0:
/git/arm-soc/drivers/gpu/host1x/hw/intr_hw.c: In function '_host1x_intr_init_host_sync':
/git/arm-soc/drivers/gpu/host1x/hw/intr_hw.c:88:197: error: call to '__compiletime_assert_88' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
make[4]: *** [drivers/gpu/host1x/hw/host1x04.o] Error 1
In file included from /git/arm-soc/drivers/gpu/host1x/hw/host1x05.c:27:0:
/git/arm-soc/drivers/gpu/host1x/hw/intr_hw.c: In function '_host1x_intr_init_host_sync':
/git/arm-soc/drivers/gpu/host1x/hw/intr_hw.c:88:197: error: call to '__compiletime_assert_88' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
make[4]: *** [drivers/gpu/host1x/hw/host1x05.o] Error 1
make[4]: Target `__build' not remade because of errors.
make[3]: *** [drivers/gpu/host1x] Error 2
/git/arm-soc/drivers/mmc/host/dw_mmc.c: In function 'dw_mci_get_ro':
/git/arm-soc/drivers/mmc/host/dw_mmc.c:1434:204: error: call to '__compiletime_assert_1434' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
/git/arm-soc/drivers/mmc/host/dw_mmc.c: In function 'dw_mci_get_cd':
/git/arm-soc/drivers/mmc/host/dw_mmc.c:1457:209: error: call to '__compiletime_assert_1457' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
/git/arm-soc/drivers/mmc/host/dw_mmc.c: In function 'dw_mci_enable_cd':
/git/arm-soc/drivers/mmc/host/dw_mmc.c:2930:223: error: call to '__compiletime_assert_2930' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
make[4]: *** [drivers/mmc/host/dw_mmc.o] Error 1
make[3]: Target `__build' not remade because of errors.
make[2]: *** [drivers/mfd] Error 2
/git/arm-soc/fs/gfs2/dir.c: In function 'get_first_leaf':
/git/arm-soc/fs/gfs2/dir.c:801:201: error: call to '__compiletime_assert_801' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
/git/arm-soc/fs/gfs2/dir.c: In function 'dir_split_leaf':
/git/arm-soc/fs/gfs2/dir.c:1017:201: error: call to '__compiletime_assert_1017' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
make[4]: *** [fs/gfs2/dir.o] Error 1
In function 'sdhci_esdhc_imx_probe_dt',
    inlined from 'sdhci_esdhc_imx_probe' at /git/arm-soc/drivers/mmc/host/sdhci-esdhc-imx.c:1213:7:
/git/arm-soc/drivers/mmc/host/sdhci-esdhc-imx.c:1014:223: error: call to '__compiletime_assert_1014' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
make[4]: *** [drivers/mmc/host/sdhci-esdhc-imx.o] Error 1
make[4]: Target `__build' not remade because of errors.
make[3]: *** [drivers/mmc/host] Error 2
make[3]: Target `__build' not remade because of errors.
make[2]: *** [drivers/mmc] Error 2
In function 'highbank_set_em_messages',
    inlined from 'ahci_highbank_probe' at /git/arm-soc/drivers/ata/sata_highbank.c:537:2:
/git/arm-soc/drivers/ata/sata_highbank.c:200:199: error: call to '__compiletime_assert_200' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
make[3]: *** [drivers/ata/sata_highbank.o] Error 1
make[4]: Target `__build' not remade because of errors.
make[3]: *** [fs/gfs2] Error 2
make[3]: Target `__build' not remade because of errors.
make[2]: *** [kernel] Error 2
make[3]: Target `__build' not remade because of errors.
make[2]: *** [drivers/ata] Error 2
/git/arm-soc/drivers/nvmem/core.c: In function 'bin_attr_nvmem_write':
/git/arm-soc/drivers/nvmem/core.c:105:197: error: call to '__compiletime_assert_105' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
/git/arm-soc/drivers/nvmem/core.c: In function 'bin_attr_nvmem_read':
/git/arm-soc/drivers/nvmem/core.c:80:196: error: call to '__compiletime_assert_80' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
/git/arm-soc/drivers/nvmem/core.c: In function '__nvmem_cell_read':
/git/arm-soc/drivers/nvmem/core.c:824:197: error: call to '__compiletime_assert_824' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
/git/arm-soc/drivers/nvmem/core.c: In function 'nvmem_device_cell_read':
/git/arm-soc/drivers/nvmem/core.c:972:197: error: call to '__compiletime_assert_972' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
/git/arm-soc/drivers/nvmem/core.c:976:197: error: call to '__compiletime_assert_976' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
/git/arm-soc/drivers/nvmem/core.c: In function 'nvmem_device_read':
/git/arm-soc/drivers/nvmem/core.c:1031:198: error: call to '__compiletime_assert_1031' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
/git/arm-soc/drivers/nvmem/core.c: In function 'nvmem_device_write':
/git/arm-soc/drivers/nvmem/core.c:1059:198: error: call to '__compiletime_assert_1059' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
/git/arm-soc/drivers/nvmem/core.c: In function 'nvmem_cell_write':
/git/arm-soc/drivers/nvmem/core.c:944:197: error: call to '__compiletime_assert_944' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
/git/arm-soc/drivers/nvmem/core.c: In function 'nvmem_device_cell_write':
/git/arm-soc/drivers/nvmem/core.c:1002:198: error: call to '__compiletime_assert_1002' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
In function 'nvmem_add_cells',
    inlined from 'nvmem_register' at /git/arm-soc/drivers/nvmem/core.c:365:3:
/git/arm-soc/drivers/nvmem/core.c:277:200: error: call to '__compiletime_assert_277' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
/git/arm-soc/drivers/nvmem/core.c: In function 'nvmem_cell_read':
/git/arm-soc/drivers/nvmem/core.c:859:197: error: call to '__compiletime_assert_859' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
make[3]: *** [drivers/nvmem/core.o] Error 1
make[3]: Target `__build' not remade because of errors.

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [PATCH v3] err.h: allow IS_ERR_VALUE to handle properly more types
  2016-02-08 12:01                 ` Arnd Bergmann
@ 2016-02-09  1:44                   ` Al Viro
  2016-02-09  8:42                   ` Andrzej Hajda
  1 sibling, 0 replies; 26+ messages in thread
From: Al Viro @ 2016-02-09  1:44 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Andrzej Hajda, Andrew Morton, Bartlomiej Zolnierkiewicz,
	Marek Szyprowski, open list, Bob Peterson

On Mon, Feb 08, 2016 at 01:01:32PM +0100, Arnd Bergmann wrote:

> /git/arm-soc/fs/afs/write.c: In function 'afs_file_write':
> /git/arm-soc/fs/afs/write.c:646:201: error: call to '__compiletime_assert_646' declared with attribute error: IS_ERR_VALUE takes an unsigned argument
> make[4]: *** [fs/afs/write.o] Error 1
> make[4]: Target `__build' not remade because of errors.
> make[3]: *** [fs/afs] Error 2

... and taking a look at that code, we see this:
        if (IS_ERR_VALUE(result)) {
                _leave(" = %zd", result);
                return result;
        }

        _leave(" = %zd", result);
        return result;

Further grep for that shows e.g.
        /* determine the length of the filename */
        nlen = romfs_dev_strnlen(sb, pos + ROMFH_SIZE, ROMFS_MAXFN);
        if (IS_ERR_VALUE(nlen))
                goto eio;
which is also fucked in head, seeing that nlen should simply have been
int there, with check being if (nlen < 0).  But that would've been
insufficiently future-proof, I suppose - what if somebody wishes to modify
romfs to allow 2Gb-long file names?

For sarcasm-impaired: use of IS_ERR_VALUE turns out to be a nice red flag.
Often of the "I'm too lazy to check the calling conventions, let's gamble on
IS_ERR_VALUE doing no harm and to hell with whoever will be scratching head
reading the results" variety...

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v3] err.h: allow IS_ERR_VALUE to handle properly more types
  2016-02-08 12:01                 ` Arnd Bergmann
  2016-02-09  1:44                   ` Al Viro
@ 2016-02-09  8:42                   ` Andrzej Hajda
  2016-02-10 21:01                     ` Arnd Bergmann
  1 sibling, 1 reply; 26+ messages in thread
From: Andrzej Hajda @ 2016-02-09  8:42 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Andrew Morton, Bartlomiej Zolnierkiewicz, Marek Szyprowski,
	open list, Bob Peterson, linux

+cc Rasmus Villemoes, I forgot to add him earlier.

On 02/08/2016 01:01 PM, Arnd Bergmann wrote:
> On Monday 08 February 2016 09:45:55 Andrzej Hajda wrote:
>> On 02/05/2016 11:52 AM, Arnd Bergmann wrote:
>>> On Thursday 04 February 2016 10:59:31 Andrew Morton wrote:
>> My version produces shortest code, Arnd's is the same as the old one.
>> On the other side Rasmus proposition seems to be the most straightforward
>> to me. Anyway I am not sure if the code length is the most important here.
>>
>> By the way .data segment size grows almost 4 times between gcc 4.4 and
>> 4.8 :)
>> Also numbers for arm64 looks interesting.
>>
>> Just for the record below all proposed implementations:
>> #define IS_ERR_VALUE_old(x) unlikely((x) >= (unsigned long)-MAX_ERRNO)
>> #define IS_ERR_VALUE_andrzej(x) ((typeof(x))(-1) <= 0 \
>>                                 ? unlikely((x) <= -1) \
>>                                 : unlikely((x) >= (typeof(x))-MAX_ERRNO))
>> #define IS_ERR_VALUE_arnd(x)      (unlikely((unsigned long long)(x) >=
>> (unsigned long long)(typeof(x))-MAX_ERRNO))
>> #define IS_ERR_VALUE_rasmus(x) ({\
>>         typeof(x) _x = (x);\
>>         unlikely(_x >= (typeof(x))-MAX_ERRNO &&  _x <= (typeof(x))-1);\
>> })
>>
>>> Andrzej's version is a little shorter on ARM because in case of signed numbers
>>> it only checks for negative values, rather than checking for values in the
>>> [-MAX_ERRNO..-1] range. I think the original behavior is more logical
>>> in this case, and my version restores it.
>> As I looked at the usage of the macro in the kernel I have not found any
>> code
>> which could benefit from the original behavior, except some buggy code in
>> staging which have already pending fix[1].
>> But maybe it would be better to use IS_ERR_VALUE to always check if err
>> is in
>> range [-MAX_ERRNO..-1] and just use simple 'err < 0' in typical case of
>> signed types.
> If we do that, should we also make it illegal to use an invalid type
> for IS_ERR()? At least that could also catch any use of 'char' and 'unsigned
> char' that are still broken.
I meant rather to make such 'policy' for future code by adding some
comment to the macro. Optionally adding compile time warning
to encourage developers to change current usage, however I am
not sure if it is not too harsh.
This way it could be also good to use your version of the macro.
It could be also good to add compiletime_assert to prevent char types
as suggested by Rasmus.

Finally it could look like:
/*
 * Use IS_ERR_VALUE only on unsigned types of at least two bytes size.
 * For signed types use '< 0' comparison.
 */
#define IS_ERR_VALUE(x)\
({\
        compiletime_assert(sizeof(x) > 1, "IS_ERR_VALUE does not handle
byte-size types");\
        compiletime_assert_warning((typeof(x))(-1) > 0, "IS_ERR_VALUE
should be called on unsigned types only, use '< 0' instead");\
        (unlikely((unsigned long long)(x) >= (unsigned long
long)(typeof(x))-MAX_ERRNO));\
})

Minor issue: there are no compile-time warning macros in kernel.
Helper provided by gcc (warning attribute) is not so nice:
optimizations removes the warning itself, preventing optimization
influences final code.
I have put my proposition of workaround below:

#define compiletime_assert_warning(cond, msg) \
({ \
        __maybe_unused void const *p = (cond) ? 0 : 1; \
})

On older compilers it issues just warning:

drivers/nvmem/core.c:1059: warning: initialization makes pointer from
integer without a cast

Since gcc 4.8 it is more verbose:

drivers/nvmem/core.c: In function ‘nvmem_device_write’:
include/linux/err.h:33:33: warning: initialization makes pointer from
integer without a cast [enabled by default]
  __maybe_unused void const *p = (cond) ? 0 : 1; \
                                 ^
include/linux/err.h:41:2: note: in expansion of macro
‘compiletime_assert_warning’
  compiletime_assert_warning((typeof(x))(-1) > 0, "IS_ERR_VALUE should
be called on unsigned types only, use '< 0' instead");\
  ^
drivers/nvmem/core.c:1059:6: note: in expansion of macro ‘IS_ERR_VALUE’
  if (IS_ERR_VALUE(rc))


Regards
Andrzej

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v3] err.h: allow IS_ERR_VALUE to handle properly more types
  2016-02-04 23:37         ` Rasmus Villemoes
@ 2016-02-10 15:16           ` Guenter Roeck
  0 siblings, 0 replies; 26+ messages in thread
From: Guenter Roeck @ 2016-02-10 15:16 UTC (permalink / raw)
  To: Rasmus Villemoes
  Cc: Andrzej Hajda, Andrew Morton, Bartlomiej Zolnierkiewicz,
	Marek Szyprowski, open list

On Fri, Feb 05, 2016 at 12:37:00AM +0100, Rasmus Villemoes wrote:
> On Wed, Feb 03 2016, Andrzej Hajda <a.hajda@samsung.com> wrote:
> 
> > Current implementation of IS_ERR_VALUE works correctly only with
> > following types:
> > - unsigned long,
> > - short, int, long.
> > Other types are handled incorrectly either on 32-bit either on 64-bit
> > either on both architectures.
> > The patch fixes it by comparing argument with MAX_ERRNO casted
> > to argument's type for unsigned types and comparing with zero for signed
> > types. As a result all integer types bigger than char are handled properly.
> >
> >
> > Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
> > ---
> > v3:
> >  - use '<= -1' instead of '< 0' to silence verbose warnings for gcc
> >    older than 4.8,
> > v2:
> >  - use '<= 0' instead of '< 0' to silence gcc verbose warnings,
> >  - expand commit message.
> > ---
> >  include/linux/err.h | 4 +++-
> >  1 file changed, 3 insertions(+), 1 deletion(-)
> >
> > diff --git a/include/linux/err.h b/include/linux/err.h
> > index 56762ab..b7d4a9f 100644
> > --- a/include/linux/err.h
> > +++ b/include/linux/err.h
> > @@ -18,7 +18,9 @@
> >  
> >  #ifndef __ASSEMBLY__
> >  
> > -#define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO)
> > +#define IS_ERR_VALUE(x) ((typeof(x))(-1) <= 0 \
> > +				? unlikely((x) <= -1) \
> > +				: unlikely((x) >= (typeof(x))-MAX_ERRNO))
> >  
> 
> I'm a bit worried that you consider any negative value an error when x
> is signed - at least that's a change which deserves some comment why
> that's ok. For example, I could imagine someone using e.g. INT_MIN as a
> sentinel return value meaning 'not an error, but something special
> still'.
> 
Theoretically maybe, but I think that is quite unlikely in the real world.

It turns out that

	if (-22 >= (unsigned long)-MAX_ERRNO)
            printf("This is odd\n");

actually does print "This is odd" (because -22 is promoted to unsigned long).

Instead of relying on such behavior, I think it would be better to convert
uses of IS_ERR_VALUE() on integer values to direct comparisons.
A coccinelle script to do that conversion that is already available for
pm functions (scripts/coccinelle/api/pm_runtime.cocci). Such a conversion
would make the code easier to read, and reduce code size instead of
(at least potentially) increasing it.

Guenter

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v3] err.h: allow IS_ERR_VALUE to handle properly more types
  2016-02-09  8:42                   ` Andrzej Hajda
@ 2016-02-10 21:01                     ` Arnd Bergmann
  2016-02-11  7:00                       ` Andrzej Hajda
  0 siblings, 1 reply; 26+ messages in thread
From: Arnd Bergmann @ 2016-02-10 21:01 UTC (permalink / raw)
  To: Andrzej Hajda
  Cc: Andrew Morton, Bartlomiej Zolnierkiewicz, Marek Szyprowski,
	open list, Bob Peterson, linux

On Tuesday 09 February 2016 09:42:26 Andrzej Hajda wrote:
> +cc Rasmus Villemoes, I forgot to add him earlier.
> 
> On 02/08/2016 01:01 PM, Arnd Bergmann wrote:
> > On Monday 08 February 2016 09:45:55 Andrzej Hajda wrote:
> >> On 02/05/2016 11:52 AM, Arnd Bergmann wrote:
> >>> On Thursday 04 February 2016 10:59:31 Andrew Morton wrote:
> >> My version produces shortest code, Arnd's is the same as the old one.
> >> On the other side Rasmus proposition seems to be the most straightforward
> >> to me. Anyway I am not sure if the code length is the most important here.
> >>
> >> By the way .data segment size grows almost 4 times between gcc 4.4 and
> >> 4.8 :)
> >> Also numbers for arm64 looks interesting.
> >>
> >> Just for the record below all proposed implementations:
> >> #define IS_ERR_VALUE_old(x) unlikely((x) >= (unsigned long)-MAX_ERRNO)
> >> #define IS_ERR_VALUE_andrzej(x) ((typeof(x))(-1) <= 0 \
> >>                                 ? unlikely((x) <= -1) \
> >>                                 : unlikely((x) >= (typeof(x))-MAX_ERRNO))
> >> #define IS_ERR_VALUE_arnd(x)      (unlikely((unsigned long long)(x) >=
> >> (unsigned long long)(typeof(x))-MAX_ERRNO))
> >> #define IS_ERR_VALUE_rasmus(x) ({\
> >>         typeof(x) _x = (x);\
> >>         unlikely(_x >= (typeof(x))-MAX_ERRNO &&  _x <= (typeof(x))-1);\
> >> })
> >>
> >>> Andrzej's version is a little shorter on ARM because in case of signed numbers
> >>> it only checks for negative values, rather than checking for values in the
> >>> [-MAX_ERRNO..-1] range. I think the original behavior is more logical
> >>> in this case, and my version restores it.
> >> As I looked at the usage of the macro in the kernel I have not found any
> >> code
> >> which could benefit from the original behavior, except some buggy code in
> >> staging which have already pending fix[1].
> >> But maybe it would be better to use IS_ERR_VALUE to always check if err
> >> is in
> >> range [-MAX_ERRNO..-1] and just use simple 'err < 0' in typical case of
> >> signed types.
> > If we do that, should we also make it illegal to use an invalid type
> > for IS_ERR()? At least that could also catch any use of 'char' and 'unsigned
> > char' that are still broken.
> I meant rather to make such 'policy' for future code by adding some
> comment to the macro. Optionally adding compile time warning
> to encourage developers to change current usage, however I am
> not sure if it is not too harsh.
> This way it could be also good to use your version of the macro.
> It could be also good to add compiletime_assert to prevent char types
> as suggested by Rasmus.
> 
> Finally it could look like:
> /*
>  * Use IS_ERR_VALUE only on unsigned types of at least two bytes size.
>  * For signed types use '< 0' comparison.
>  */
> #define IS_ERR_VALUE(x)\
> ({\
>         compiletime_assert(sizeof(x) > 1, "IS_ERR_VALUE does not handle
> byte-size types");\
>         compiletime_assert_warning((typeof(x))(-1) > 0, "IS_ERR_VALUE
> should be called on unsigned types only, use '< 0' instead");\
>         (unlikely((unsigned long long)(x) >= (unsigned long
> long)(typeof(x))-MAX_ERRNO));\
> })
> 

I think the easiest way to express this would be to ensure that the argument
is 'unsigned long', like:

#define IS_ERR_VALUE(x) ((unsigned long*)NULL == (typeof (x)*)NULL && \
       unlikely((unsigned long long)(x) >= (unsigned long long)(typeof(x))-MAX_ERRNO))


I tried to figure out where that would take as, as we then have to change
all users of IS_ERR_VALUE() that don't use an 'unsigned long' argument, not
just the ones that use one of the forbidden types (long long, unsigned long long,
unsigned int, unsigned short, char, unsigned char, signed char).

The patch below modifies all drivers that see newly introduced warnings with
the version above. Most of them pass an 'int' into IS_ERR_VALUE(), which currently
works as expected.

There are probably a couple of other architecture-specific files using IS_ERR_VALUE()
that I did not catch with ARM allmodocnfig and randconfig builds.

	Arnd

 drivers/ata/sata_highbank.c                      |  2 +-
 drivers/char/mem.c                               |  2 +-
 drivers/cpufreq/omap-cpufreq.c                   |  2 +-
 drivers/crypto/caam/ctrl.c                       |  2 +-
 drivers/dma/sun4i-dma.c                          | 16 ++++++++--------
 drivers/gpu/drm/sti/sti_vtg.c                    |  4 ++--
 drivers/gpu/drm/tilcdc/tilcdc_tfp410.c           |  2 +-
 drivers/gpu/host1x/hw/intr_hw.c                  |  2 +-
 drivers/iommu/arm-smmu.c                         |  8 ++++----
 drivers/irqchip/irq-clps711x.c                   |  2 +-
 drivers/irqchip/irq-gic.c                        |  2 +-
 drivers/irqchip/irq-hip04.c                      |  2 +-
 drivers/media/i2c/adp1653.c                      | 10 +++++-----
 drivers/media/platform/s5p-tv/mixer_drv.c        |  2 +-
 drivers/media/platform/soc_camera/atmel-isi.c    |  2 +-
 drivers/mfd/twl4030-irq.c                        |  2 +-
 drivers/mmc/core/mmc.c                           |  4 ++--
 drivers/mmc/host/dw_mmc.c                        |  6 +++---
 drivers/mmc/host/sdhci-esdhc-imx.c               |  2 +-
 drivers/mmc/host/sdhci.c                         |  4 ++--
 drivers/net/ethernet/freescale/fman/fman.c       |  2 +-
 drivers/net/ethernet/freescale/fman/fman_muram.c |  4 ++--
 drivers/net/ethernet/freescale/fman/fman_muram.h |  4 ++--
 drivers/net/wireless/ti/wlcore/spi.c             |  4 ++--
 drivers/nvmem/core.c                             | 22 +++++++++++-----------
 drivers/staging/lustre/lnet/lnet/acceptor.c      |  4 ++--
 drivers/staging/lustre/lnet/lnet/router.c        |  4 ++--
 drivers/staging/lustre/lustre/llite/statahead.c  |  4 ++--
 drivers/staging/lustre/lustre/mdc/mdc_request.c  |  4 ++--
 drivers/staging/lustre/lustre/mgc/mgc_request.c  |  4 ++--
 drivers/staging/lustre/lustre/obdclass/llog.c    |  4 ++--
 drivers/staging/lustre/lustre/ptlrpc/pinger.c    |  4 ++--
 drivers/staging/lustre/lustre/ptlrpc/service.c   | 10 +++++-----
 drivers/tty/serial/amba-pl011.c                  |  2 +-
 drivers/tty/serial/clps711x.c                    |  4 ++--
 drivers/tty/serial/digicolor-usart.c             |  2 +-
 drivers/video/fbdev/da8xx-fb.c                   |  4 ++--
 drivers/video/fbdev/exynos/exynos_mipi_dsi.c     |  2 +-
 fs/afs/write.c                                   |  4 ----
 fs/gfs2/dir.c                                    |  4 ++--
 include/linux/err.h                              |  3 ++-
 kernel/pid.c                                     |  2 +-
 net/9p/client.c                                  |  4 ++--
 net/ipv4/netfilter/arp_tables.c                  |  2 +-
 net/ipv4/netfilter/ip_tables.c                   |  2 +-
 net/ipv6/netfilter/ip6_tables.c                  |  2 +-
 sound/soc/qcom/lpass-platform.c                  |  2 +-
 47 files changed, 94 insertions(+), 97 deletions(-)

diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c
index 8638d575b2b9..aafb8cc03523 100644
--- a/drivers/ata/sata_highbank.c
+++ b/drivers/ata/sata_highbank.c
@@ -197,7 +197,7 @@ static void highbank_set_em_messages(struct device *dev,
 
 	for (i = 0; i < SGPIO_PINS; i++) {
 		err = of_get_named_gpio(np, "calxeda,sgpio-gpio", i);
-		if (IS_ERR_VALUE(err))
+		if (err < 0)
 			return;
 
 		pdata->sgpio_gpio[i] = err;
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 4f6f94c43412..3ffd3e32051b 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -695,7 +695,7 @@ static loff_t memory_lseek(struct file *file, loff_t offset, int orig)
 		offset += file->f_pos;
 	case SEEK_SET:
 		/* to avoid userland mistaking f_pos=-9 as -EBADF=-9 */
-		if (IS_ERR_VALUE((unsigned long long)offset)) {
+		if (offset > (unsigned long long)-MAX_ERRNO) {
 			ret = -EOVERFLOW;
 			break;
 		}
diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c
index e3866e0d5bf8..c182c8c84b8d 100644
--- a/drivers/cpufreq/omap-cpufreq.c
+++ b/drivers/cpufreq/omap-cpufreq.c
@@ -51,7 +51,7 @@ static int omap_target(struct cpufreq_policy *policy, unsigned int index)
 
 	freq = new_freq * 1000;
 	ret = clk_round_rate(policy->clk, freq);
-	if (IS_ERR_VALUE(ret)) {
+	if (ret < 0) {
 		dev_warn(mpu_dev,
 			 "CPUfreq: Cannot find matching frequency for %lu\n",
 			 freq);
diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c
index 44d30b45f3cc..5ad5f3009ae0 100644
--- a/drivers/crypto/caam/ctrl.c
+++ b/drivers/crypto/caam/ctrl.c
@@ -402,7 +402,7 @@ int caam_get_era(void)
 	ret = of_property_read_u32(caam_node, "fsl,sec-era", &prop);
 	of_node_put(caam_node);
 
-	return IS_ERR_VALUE(ret) ? -ENOTSUPP : prop;
+	return ret ? -ENOTSUPP : prop;
 }
 EXPORT_SYMBOL(caam_get_era);
 
diff --git a/drivers/dma/sun4i-dma.c b/drivers/dma/sun4i-dma.c
index 1661d518224a..4dc7a686af1c 100644
--- a/drivers/dma/sun4i-dma.c
+++ b/drivers/dma/sun4i-dma.c
@@ -461,25 +461,25 @@ generate_ndma_promise(struct dma_chan *chan, dma_addr_t src, dma_addr_t dest,
 
 	/* Source burst */
 	ret = convert_burst(sconfig->src_maxburst);
-	if (IS_ERR_VALUE(ret))
+	if (ret < 0)
 		goto fail;
 	promise->cfg |= SUN4I_DMA_CFG_SRC_BURST_LENGTH(ret);
 
 	/* Destination burst */
 	ret = convert_burst(sconfig->dst_maxburst);
-	if (IS_ERR_VALUE(ret))
+	if (ret < 0)
 		goto fail;
 	promise->cfg |= SUN4I_DMA_CFG_DST_BURST_LENGTH(ret);
 
 	/* Source bus width */
 	ret = convert_buswidth(sconfig->src_addr_width);
-	if (IS_ERR_VALUE(ret))
+	if (ret < 0)
 		goto fail;
 	promise->cfg |= SUN4I_DMA_CFG_SRC_DATA_WIDTH(ret);
 
 	/* Destination bus width */
 	ret = convert_buswidth(sconfig->dst_addr_width);
-	if (IS_ERR_VALUE(ret))
+	if (ret < 0)
 		goto fail;
 	promise->cfg |= SUN4I_DMA_CFG_DST_DATA_WIDTH(ret);
 
@@ -518,25 +518,25 @@ generate_ddma_promise(struct dma_chan *chan, dma_addr_t src, dma_addr_t dest,
 
 	/* Source burst */
 	ret = convert_burst(sconfig->src_maxburst);
-	if (IS_ERR_VALUE(ret))
+	if (ret < 0)
 		goto fail;
 	promise->cfg |= SUN4I_DMA_CFG_SRC_BURST_LENGTH(ret);
 
 	/* Destination burst */
 	ret = convert_burst(sconfig->dst_maxburst);
-	if (IS_ERR_VALUE(ret))
+	if (ret < 0)
 		goto fail;
 	promise->cfg |= SUN4I_DMA_CFG_DST_BURST_LENGTH(ret);
 
 	/* Source bus width */
 	ret = convert_buswidth(sconfig->src_addr_width);
-	if (IS_ERR_VALUE(ret))
+	if (ret < 0)
 		goto fail;
 	promise->cfg |= SUN4I_DMA_CFG_SRC_DATA_WIDTH(ret);
 
 	/* Destination bus width */
 	ret = convert_buswidth(sconfig->dst_addr_width);
-	if (IS_ERR_VALUE(ret))
+	if (ret < 0)
 		goto fail;
 	promise->cfg |= SUN4I_DMA_CFG_DST_DATA_WIDTH(ret);
 
diff --git a/drivers/gpu/drm/sti/sti_vtg.c b/drivers/gpu/drm/sti/sti_vtg.c
index d56630c60039..71c03ea20e32 100644
--- a/drivers/gpu/drm/sti/sti_vtg.c
+++ b/drivers/gpu/drm/sti/sti_vtg.c
@@ -355,7 +355,7 @@ static int vtg_probe(struct platform_device *pdev)
 			return -EPROBE_DEFER;
 	} else {
 		vtg->irq = platform_get_irq(pdev, 0);
-		if (IS_ERR_VALUE(vtg->irq)) {
+		if (vtg->irq < 0) {
 			DRM_ERROR("Failed to get VTG interrupt\n");
 			return vtg->irq;
 		}
@@ -365,7 +365,7 @@ static int vtg_probe(struct platform_device *pdev)
 		ret = devm_request_threaded_irq(dev, vtg->irq, vtg_irq,
 				vtg_irq_thread, IRQF_ONESHOT,
 				dev_name(dev), vtg);
-		if (IS_ERR_VALUE(ret)) {
+		if (ret < 0) {
 			DRM_ERROR("Failed to register VTG interrupt\n");
 			return ret;
 		}
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c b/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c
index 5052a8af7ecb..7e4f56254af7 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c
@@ -359,7 +359,7 @@ static int tfp410_probe(struct platform_device *pdev)
 
 	tfp410_mod->gpio = of_get_named_gpio_flags(node, "powerdn-gpio",
 			0, NULL);
-	if (IS_ERR_VALUE(tfp410_mod->gpio)) {
+	if (tfp410_mod->gpio < 0) {
 		dev_warn(&pdev->dev, "No power down GPIO\n");
 	} else {
 		ret = gpio_request(tfp410_mod->gpio, "DVI_PDn");
diff --git a/drivers/gpu/host1x/hw/intr_hw.c b/drivers/gpu/host1x/hw/intr_hw.c
index 498b37e39058..e1e31e9e67cd 100644
--- a/drivers/gpu/host1x/hw/intr_hw.c
+++ b/drivers/gpu/host1x/hw/intr_hw.c
@@ -85,7 +85,7 @@ static int _host1x_intr_init_host_sync(struct host1x *host, u32 cpm,
 	err = devm_request_irq(host->dev, host->intr_syncpt_irq,
 			       syncpt_thresh_isr, IRQF_SHARED,
 			       "host1x_syncpt", host);
-	if (IS_ERR_VALUE(err)) {
+	if (err < 0) {
 		WARN_ON(1);
 		return err;
 	}
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 59ee4b8a3236..f6750772f6d8 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -874,7 +874,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
 
 	ret = __arm_smmu_alloc_bitmap(smmu->context_map, start,
 				      smmu->num_context_banks);
-	if (IS_ERR_VALUE(ret))
+	if (ret < 0)
 		goto out_unlock;
 
 	cfg->cbndx = ret;
@@ -913,7 +913,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
 	irq = smmu->irqs[smmu->num_global_irqs + cfg->irptndx];
 	ret = request_irq(irq, arm_smmu_context_fault, IRQF_SHARED,
 			  "arm-smmu-context-fault", domain);
-	if (IS_ERR_VALUE(ret)) {
+	if (ret < 0) {
 		dev_err(smmu->dev, "failed to request context IRQ %d (%u)\n",
 			cfg->irptndx, irq);
 		cfg->irptndx = INVALID_IRPTNDX;
@@ -1016,7 +1016,7 @@ static int arm_smmu_master_configure_smrs(struct arm_smmu_device *smmu,
 	for (i = 0; i < cfg->num_streamids; ++i) {
 		int idx = __arm_smmu_alloc_bitmap(smmu->smr_map, 0,
 						  smmu->num_mapping_groups);
-		if (IS_ERR_VALUE(idx)) {
+		if (idx < 0) {
 			dev_err(smmu->dev, "failed to allocate free SMR\n");
 			goto err_free_smrs;
 		}
@@ -1136,7 +1136,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
 
 	/* Ensure that the domain is finalised */
 	ret = arm_smmu_init_domain_context(domain, smmu);
-	if (IS_ERR_VALUE(ret))
+	if (ret < 0)
 		return ret;
 
 	/*
diff --git a/drivers/irqchip/irq-clps711x.c b/drivers/irqchip/irq-clps711x.c
index eb5eb0cd414d..2223b3f15d68 100644
--- a/drivers/irqchip/irq-clps711x.c
+++ b/drivers/irqchip/irq-clps711x.c
@@ -182,7 +182,7 @@ static int __init _clps711x_intc_init(struct device_node *np,
 	writel_relaxed(0, clps711x_intc->intmr[2]);
 
 	err = irq_alloc_descs(-1, 0, ARRAY_SIZE(clps711x_irqs), numa_node_id());
-	if (IS_ERR_VALUE(err))
+	if (err < 0)
 		goto out_iounmap;
 
 	clps711x_intc->ops.map = clps711x_intc_irq_map;
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 911758c056c1..355d0779bec0 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -1103,7 +1103,7 @@ static void __init __gic_init_bases(unsigned int gic_nr, int irq_start,
 
 		irq_base = irq_alloc_descs(irq_start, 16, gic_irqs,
 					   numa_node_id());
-		if (IS_ERR_VALUE(irq_base)) {
+		if (irq_base < 0) {
 			WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
 			     irq_start);
 			irq_base = irq_start;
diff --git a/drivers/irqchip/irq-hip04.c b/drivers/irqchip/irq-hip04.c
index 9688d2e2a636..9e25d8ce08e5 100644
--- a/drivers/irqchip/irq-hip04.c
+++ b/drivers/irqchip/irq-hip04.c
@@ -402,7 +402,7 @@ hip04_of_init(struct device_node *node, struct device_node *parent)
 	nr_irqs -= hwirq_base; /* calculate # of irqs to allocate */
 
 	irq_base = irq_alloc_descs(-1, hwirq_base, nr_irqs, numa_node_id());
-	if (IS_ERR_VALUE(irq_base)) {
+	if (irq_base < 0) {
 		pr_err("failed to allocate IRQ numbers\n");
 		return -EINVAL;
 	}
diff --git a/drivers/media/i2c/adp1653.c b/drivers/media/i2c/adp1653.c
index 7e9cbf757e95..efa1c11f8f0b 100644
--- a/drivers/media/i2c/adp1653.c
+++ b/drivers/media/i2c/adp1653.c
@@ -95,7 +95,7 @@ static int adp1653_get_fault(struct adp1653_flash *flash)
 	int rval;
 
 	fault = i2c_smbus_read_byte_data(client, ADP1653_REG_FAULT);
-	if (IS_ERR_VALUE(fault))
+	if (fault < 0)
 		return fault;
 
 	flash->fault |= fault;
@@ -105,13 +105,13 @@ static int adp1653_get_fault(struct adp1653_flash *flash)
 
 	/* Clear faults. */
 	rval = i2c_smbus_write_byte_data(client, ADP1653_REG_OUT_SEL, 0);
-	if (IS_ERR_VALUE(rval))
+	if (rval < 0)
 		return rval;
 
 	flash->led_mode->val = V4L2_FLASH_LED_MODE_NONE;
 
 	rval = adp1653_update_hw(flash);
-	if (IS_ERR_VALUE(rval))
+	if (rval)
 		return rval;
 
 	return flash->fault;
@@ -158,7 +158,7 @@ static int adp1653_get_ctrl(struct v4l2_ctrl *ctrl)
 	int rval;
 
 	rval = adp1653_get_fault(flash);
-	if (IS_ERR_VALUE(rval))
+	if (rval)
 		return rval;
 
 	ctrl->cur.val = 0;
@@ -184,7 +184,7 @@ static int adp1653_set_ctrl(struct v4l2_ctrl *ctrl)
 	int rval;
 
 	rval = adp1653_get_fault(flash);
-	if (IS_ERR_VALUE(rval))
+	if (rval)
 		return rval;
 	if ((rval & (ADP1653_REG_FAULT_FLT_SCP |
 		     ADP1653_REG_FAULT_FLT_OT |
diff --git a/drivers/media/platform/s5p-tv/mixer_drv.c b/drivers/media/platform/s5p-tv/mixer_drv.c
index 5ef67774971d..8a5d19469ddc 100644
--- a/drivers/media/platform/s5p-tv/mixer_drv.c
+++ b/drivers/media/platform/s5p-tv/mixer_drv.c
@@ -146,7 +146,7 @@ int mxr_power_get(struct mxr_device *mdev)
 
 	/* returning 1 means that power is already enabled,
 	 * so zero success be returned */
-	if (IS_ERR_VALUE(ret))
+	if (ret < 0)
 		return ret;
 	return 0;
 }
diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c
index 1af779ee3c74..fbc8f633521e 100644
--- a/drivers/media/platform/soc_camera/atmel-isi.c
+++ b/drivers/media/platform/soc_camera/atmel-isi.c
@@ -1086,7 +1086,7 @@ static int atmel_isi_probe(struct platform_device *pdev)
 		isi->width_flags |= 1 << 9;
 
 	irq = platform_get_irq(pdev, 0);
-	if (IS_ERR_VALUE(irq)) {
+	if (irq < 0) {
 		ret = irq;
 		goto err_req_irq;
 	}
diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c
index 40e51b0baa46..b46c0cfc27d9 100644
--- a/drivers/mfd/twl4030-irq.c
+++ b/drivers/mfd/twl4030-irq.c
@@ -696,7 +696,7 @@ int twl4030_init_irq(struct device *dev, int irq_num)
 	nr_irqs = TWL4030_PWR_NR_IRQS + TWL4030_CORE_NR_IRQS;
 
 	irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
-	if (IS_ERR_VALUE(irq_base)) {
+	if (irq_base < 0) {
 		dev_err(dev, "Fail to allocate IRQ descs\n");
 		return irq_base;
 	}
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 4dbe3df8024b..6304883f35a2 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1268,7 +1268,7 @@ static int mmc_select_hs200(struct mmc_card *card)
 	 * switch to HS200 mode if bus width is set successfully.
 	 */
 	err = mmc_select_bus_width(card);
-	if (!IS_ERR_VALUE(err)) {
+	if (!err) {
 		val = EXT_CSD_TIMING_HS200 |
 		      card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
 		err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
@@ -1577,7 +1577,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 	} else if (mmc_card_hs(card)) {
 		/* Select the desired bus width optionally */
 		err = mmc_select_bus_width(card);
-		if (!IS_ERR_VALUE(err)) {
+		if (!err) {
 			err = mmc_select_hs_ddr(card);
 			if (err)
 				goto free_card;
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 242f9a0769bd..a4cbbfe1eabe 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1431,7 +1431,7 @@ static int dw_mci_get_ro(struct mmc_host *mmc)
 	int gpio_ro = mmc_gpio_get_ro(mmc);
 
 	/* Use platform get_ro function, else try on board write protect */
-	if (!IS_ERR_VALUE(gpio_ro))
+	if (gpio_ro >= 0)
 		read_only = gpio_ro;
 	else
 		read_only =
@@ -1454,7 +1454,7 @@ static int dw_mci_get_cd(struct mmc_host *mmc)
 	if ((mmc->caps & MMC_CAP_NEEDS_POLL) ||
 	    (mmc->caps & MMC_CAP_NONREMOVABLE))
 		present = 1;
-	else if (!IS_ERR_VALUE(gpio_cd))
+	else if (gpio_cd >= 0)
 		present = gpio_cd;
 	else
 		present = (mci_readl(slot->host, CDETECT) & (1 << slot->id))
@@ -2927,7 +2927,7 @@ static void dw_mci_enable_cd(struct dw_mci *host)
 		if (slot->mmc->caps & MMC_CAP_NEEDS_POLL)
 			return;
 
-		if (IS_ERR_VALUE(mmc_gpio_get_cd(slot->mmc)))
+		if (mmc_gpio_get_cd(slot->mmc) < 0)
 			break;
 	}
 	if (i == host->num_slots)
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index f25f29253595..22e47ab06e9f 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -1011,7 +1011,7 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
 	if (ret)
 		return ret;
 
-	if (!IS_ERR_VALUE(mmc_gpio_get_cd(host->mmc)))
+	if (mmc_gpio_get_cd(host->mmc) >= 0)
 		host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
 
 	return 0;
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index d622435d1bcc..8f1dca39a940 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1625,7 +1625,7 @@ static int sdhci_do_get_cd(struct sdhci_host *host)
 	 * Try slot gpio detect, if defined it take precedence
 	 * over build in controller functionality
 	 */
-	if (!IS_ERR_VALUE(gpio_cd))
+	if (gpio_cd >= 0)
 		return !!gpio_cd;
 
 	/* If polling, assume that the card is always present. */
@@ -3114,7 +3114,7 @@ int sdhci_add_host(struct sdhci_host *host)
 
 	if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) &&
 	    !(mmc->caps & MMC_CAP_NONREMOVABLE) &&
-	    IS_ERR_VALUE(mmc_gpio_get_cd(host->mmc)))
+	    mmc_gpio_get_cd(host->mmc) < 0)
 		mmc->caps |= MMC_CAP_NEEDS_POLL;
 
 	/* If there are external regulators, get them */
diff --git a/drivers/net/ethernet/freescale/fman/fman.c b/drivers/net/ethernet/freescale/fman/fman.c
index 623aa1c8ebc6..f1a5f2a805ec 100644
--- a/drivers/net/ethernet/freescale/fman/fman.c
+++ b/drivers/net/ethernet/freescale/fman/fman.c
@@ -614,7 +614,7 @@ struct fman {
 	struct fman_cfg *cfg;
 	struct muram_info *muram;
 	/* cam section in muram */
-	int cam_offset;
+	unsigned long cam_offset;
 	size_t cam_size;
 	/* Fifo in MURAM */
 	int fifo_offset;
diff --git a/drivers/net/ethernet/freescale/fman/fman_muram.c b/drivers/net/ethernet/freescale/fman/fman_muram.c
index 4eb0e9ac7182..47394c45b6e8 100644
--- a/drivers/net/ethernet/freescale/fman/fman_muram.c
+++ b/drivers/net/ethernet/freescale/fman/fman_muram.c
@@ -129,7 +129,7 @@ unsigned long fman_muram_offset_to_vbase(struct muram_info *muram,
  *
  * Return: address of the allocated memory; NULL otherwise.
  */
-int fman_muram_alloc(struct muram_info *muram, size_t size)
+unsigned long fman_muram_alloc(struct muram_info *muram, size_t size)
 {
 	unsigned long vaddr;
 
@@ -150,7 +150,7 @@ int fman_muram_alloc(struct muram_info *muram, size_t size)
  *
  * Free an allocated memory from FM-MURAM partition.
  */
-void fman_muram_free_mem(struct muram_info *muram, u32 offset, size_t size)
+void fman_muram_free_mem(struct muram_info *muram, unsigned long offset, size_t size)
 {
 	unsigned long addr = fman_muram_offset_to_vbase(muram, offset);
 
diff --git a/drivers/net/ethernet/freescale/fman/fman_muram.h b/drivers/net/ethernet/freescale/fman/fman_muram.h
index dbf0af9e5bb5..889649ad8931 100644
--- a/drivers/net/ethernet/freescale/fman/fman_muram.h
+++ b/drivers/net/ethernet/freescale/fman/fman_muram.h
@@ -44,8 +44,8 @@ struct muram_info *fman_muram_init(phys_addr_t base, size_t size);
 unsigned long fman_muram_offset_to_vbase(struct muram_info *muram,
 					 unsigned long offset);
 
-int fman_muram_alloc(struct muram_info *muram, size_t size);
+unsigned long fman_muram_alloc(struct muram_info *muram, size_t size);
 
-void fman_muram_free_mem(struct muram_info *muram, u32 offset, size_t size);
+void fman_muram_free_mem(struct muram_info *muram, unsigned long offset, size_t size);
 
 #endif /* __FM_MURAM_EXT */
diff --git a/drivers/net/wireless/ti/wlcore/spi.c b/drivers/net/wireless/ti/wlcore/spi.c
index 020ac1a4b408..cea9443c22a6 100644
--- a/drivers/net/wireless/ti/wlcore/spi.c
+++ b/drivers/net/wireless/ti/wlcore/spi.c
@@ -382,7 +382,7 @@ static int wlcore_probe_of(struct spi_device *spi, struct wl12xx_spi_glue *glue,
 
 	ret = of_property_read_u32(dt_node, "ref-clock-frequency",
 				   &pdev_data->ref_clock_freq);
-	if (IS_ERR_VALUE(ret)) {
+	if (ret) {
 		dev_err(glue->dev,
 			"can't get reference clock frequency (%d)\n", ret);
 		return ret;
@@ -425,7 +425,7 @@ static int wl1271_probe(struct spi_device *spi)
 	}
 
 	ret = wlcore_probe_of(spi, glue, &pdev_data);
-	if (IS_ERR_VALUE(ret)) {
+	if (ret) {
 		dev_err(glue->dev,
 			"can't get device tree parameters (%d)\n", ret);
 		return ret;
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index 9d11d9837312..69f2c6391ec5 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -80,7 +80,7 @@ static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj,
 
 	rc = regmap_raw_read(nvmem->regmap, pos, buf, count);
 
-	if (IS_ERR_VALUE(rc))
+	if (rc)
 		return rc;
 
 	return count;
@@ -108,7 +108,7 @@ static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj,
 
 	rc = regmap_raw_write(nvmem->regmap, pos, buf, count);
 
-	if (IS_ERR_VALUE(rc))
+	if (rc)
 		return rc;
 
 	return count;
@@ -280,7 +280,7 @@ static int nvmem_add_cells(struct nvmem_device *nvmem,
 		}
 
 		rval = nvmem_cell_info_to_nvmem_cell(nvmem, &info[i], cells[i]);
-		if (IS_ERR_VALUE(rval)) {
+		if (rval) {
 			kfree(cells[i]);
 			goto err;
 		}
@@ -827,7 +827,7 @@ static int __nvmem_cell_read(struct nvmem_device *nvmem,
 
 	rc = regmap_raw_read(nvmem->regmap, cell->offset, buf, cell->bytes);
 
-	if (IS_ERR_VALUE(rc))
+	if (rc)
 		return rc;
 
 	/* shift bits in-place */
@@ -862,7 +862,7 @@ void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len)
 		return ERR_PTR(-ENOMEM);
 
 	rc = __nvmem_cell_read(nvmem, cell, buf, len);
-	if (IS_ERR_VALUE(rc)) {
+	if (rc) {
 		kfree(buf);
 		return ERR_PTR(rc);
 	}
@@ -947,7 +947,7 @@ int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len)
 	if (cell->bit_offset || cell->nbits)
 		kfree(buf);
 
-	if (IS_ERR_VALUE(rc))
+	if (rc)
 		return rc;
 
 	return len;
@@ -975,11 +975,11 @@ ssize_t nvmem_device_cell_read(struct nvmem_device *nvmem,
 		return -EINVAL;
 
 	rc = nvmem_cell_info_to_nvmem_cell(nvmem, info, &cell);
-	if (IS_ERR_VALUE(rc))
+	if (rc)
 		return rc;
 
 	rc = __nvmem_cell_read(nvmem, &cell, buf, &len);
-	if (IS_ERR_VALUE(rc))
+	if (rc)
 		return rc;
 
 	return len;
@@ -1005,7 +1005,7 @@ int nvmem_device_cell_write(struct nvmem_device *nvmem,
 		return -EINVAL;
 
 	rc = nvmem_cell_info_to_nvmem_cell(nvmem, info, &cell);
-	if (IS_ERR_VALUE(rc))
+	if (rc)
 		return rc;
 
 	return nvmem_cell_write(&cell, buf, cell.bytes);
@@ -1034,7 +1034,7 @@ int nvmem_device_read(struct nvmem_device *nvmem,
 
 	rc = regmap_raw_read(nvmem->regmap, offset, buf, bytes);
 
-	if (IS_ERR_VALUE(rc))
+	if (rc)
 		return rc;
 
 	return bytes;
@@ -1062,7 +1062,7 @@ int nvmem_device_write(struct nvmem_device *nvmem,
 
 	rc = regmap_raw_write(nvmem->regmap, offset, buf, bytes);
 
-	if (IS_ERR_VALUE(rc))
+	if (rc)
 		return rc;
 
 
diff --git a/drivers/staging/lustre/lnet/lnet/acceptor.c b/drivers/staging/lustre/lnet/lnet/acceptor.c
index fed57d90028d..78c3a5323295 100644
--- a/drivers/staging/lustre/lnet/lnet/acceptor.c
+++ b/drivers/staging/lustre/lnet/lnet/acceptor.c
@@ -454,10 +454,10 @@ lnet_acceptor_start(void)
 	if (lnet_count_acceptor_nis() == 0)  /* not required */
 		return 0;
 
-	rc2 = PTR_ERR(kthread_run(lnet_acceptor,
+	rc2 = PTR_ERR_OR_ZERO(kthread_run(lnet_acceptor,
 				  (void *)(ulong_ptr_t)secure,
 				  "acceptor_%03ld", secure));
-	if (IS_ERR_VALUE(rc2)) {
+	if (rc2) {
 		CERROR("Can't start acceptor thread: %ld\n", rc2);
 
 		return -ESRCH;
diff --git a/drivers/staging/lustre/lnet/lnet/router.c b/drivers/staging/lustre/lnet/lnet/router.c
index f5faa414d250..2a8a684c5fb8 100644
--- a/drivers/staging/lustre/lnet/lnet/router.c
+++ b/drivers/staging/lustre/lnet/lnet/router.c
@@ -1029,9 +1029,9 @@ lnet_router_checker_start(void)
 	}
 
 	the_lnet.ln_rc_state = LNET_RC_STATE_RUNNING;
-	rc = PTR_ERR(kthread_run(lnet_router_checker,
+	rc = PTR_ERR_OR_ZERO(kthread_run(lnet_router_checker,
 				 NULL, "router_checker"));
-	if (IS_ERR_VALUE(rc)) {
+	if (rc) {
 		CERROR("Can't start router checker thread: %d\n", rc);
 		/* block until event callback signals exit */
 		down(&the_lnet.ln_rc_signal);
diff --git a/drivers/staging/lustre/lustre/llite/statahead.c b/drivers/staging/lustre/lustre/llite/statahead.c
index 88ffd8e3abdb..e69b45f13799 100644
--- a/drivers/staging/lustre/lustre/llite/statahead.c
+++ b/drivers/staging/lustre/lustre/llite/statahead.c
@@ -1656,10 +1656,10 @@ int do_statahead_enter(struct inode *dir, struct dentry **dentryp,
 	lli->lli_sai = sai;
 
 	plli = ll_i2info(d_inode(parent));
-	rc = PTR_ERR(kthread_run(ll_statahead_thread, parent,
+	rc = PTR_ERR_OR_ZERO(kthread_run(ll_statahead_thread, parent,
 				 "ll_sa_%u", plli->lli_opendir_pid));
 	thread = &sai->sai_thread;
-	if (IS_ERR_VALUE(rc)) {
+	if (rc) {
 		CERROR("can't start ll_sa thread, rc: %d\n", rc);
 		dput(parent);
 		lli->lli_opendir_key = NULL;
diff --git a/drivers/staging/lustre/lustre/mdc/mdc_request.c b/drivers/staging/lustre/lustre/mdc/mdc_request.c
index 43481278096f..7b1445c6ea5f 100644
--- a/drivers/staging/lustre/lustre/mdc/mdc_request.c
+++ b/drivers/staging/lustre/lustre/mdc/mdc_request.c
@@ -1571,9 +1571,9 @@ static int mdc_ioc_changelog_send(struct obd_device *obd,
 	 * New thread because we should return to user app before
 	 * writing into our pipe
 	 */
-	rc = PTR_ERR(kthread_run(mdc_changelog_send_thread, cs,
+	rc = PTR_ERR_OR_ZERO(kthread_run(mdc_changelog_send_thread, cs,
 				 "mdc_clg_send_thread"));
-	if (!IS_ERR_VALUE(rc)) {
+	if (!rc) {
 		CDEBUG(D_CHANGELOG, "start changelog thread\n");
 		return 0;
 	}
diff --git a/drivers/staging/lustre/lustre/mgc/mgc_request.c b/drivers/staging/lustre/lustre/mgc/mgc_request.c
index ab4800c20a95..815b33c8fd97 100644
--- a/drivers/staging/lustre/lustre/mgc/mgc_request.c
+++ b/drivers/staging/lustre/lustre/mgc/mgc_request.c
@@ -734,9 +734,9 @@ static int mgc_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
 		init_waitqueue_head(&rq_waitq);
 
 		/* start requeue thread */
-		rc = PTR_ERR(kthread_run(mgc_requeue_thread, NULL,
+		rc = PTR_ERR_OR_ZERO(kthread_run(mgc_requeue_thread, NULL,
 					     "ll_cfg_requeue"));
-		if (IS_ERR_VALUE(rc)) {
+		if (rc) {
 			CERROR("%s: Cannot start requeue thread (%d),no more log updates!\n",
 			       obd->obd_name, rc);
 			goto err_cleanup;
diff --git a/drivers/staging/lustre/lustre/obdclass/llog.c b/drivers/staging/lustre/lustre/obdclass/llog.c
index f956d7ed6785..91230c84ad6d 100644
--- a/drivers/staging/lustre/lustre/obdclass/llog.c
+++ b/drivers/staging/lustre/lustre/obdclass/llog.c
@@ -380,9 +380,9 @@ int llog_process_or_fork(const struct lu_env *env,
 		 * init the new one in llog_process_thread_daemonize. */
 		lpi->lpi_env = NULL;
 		init_completion(&lpi->lpi_completion);
-		rc = PTR_ERR(kthread_run(llog_process_thread_daemonize, lpi,
+		rc = PTR_ERR_OR_ZERO(kthread_run(llog_process_thread_daemonize, lpi,
 					     "llog_process_thread"));
-		if (IS_ERR_VALUE(rc)) {
+		if (rc) {
 			CERROR("%s: cannot start thread: rc = %d\n",
 			       loghandle->lgh_ctxt->loc_obd->obd_name, rc);
 			kfree(lpi);
diff --git a/drivers/staging/lustre/lustre/ptlrpc/pinger.c b/drivers/staging/lustre/lustre/ptlrpc/pinger.c
index fb2d5236a971..5b7743b9f48f 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/pinger.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/pinger.c
@@ -303,9 +303,9 @@ int ptlrpc_start_pinger(void)
 
 	strcpy(pinger_thread.t_name, "ll_ping");
 
-	rc = PTR_ERR(kthread_run(ptlrpc_pinger_main, &pinger_thread,
+	rc = PTR_ERR_OR_ZERO(kthread_run(ptlrpc_pinger_main, &pinger_thread,
 				 "%s", pinger_thread.t_name));
-	if (IS_ERR_VALUE(rc)) {
+	if (rc) {
 		CERROR("cannot start thread: %d\n", rc);
 		return rc;
 	}
diff --git a/drivers/staging/lustre/lustre/ptlrpc/service.c b/drivers/staging/lustre/lustre/ptlrpc/service.c
index 8598300a61d1..8ca33f9dbf42 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/service.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/service.c
@@ -2256,17 +2256,17 @@ static int ptlrpc_start_hr_threads(void)
 		for (j = 0; j < hrp->hrp_nthrs; j++) {
 			struct	ptlrpc_hr_thread *hrt = &hrp->hrp_thrs[j];
 
-			rc = PTR_ERR(kthread_run(ptlrpc_hr_main,
+			rc = PTR_ERR_OR_ZERO(kthread_run(ptlrpc_hr_main,
 						 &hrp->hrp_thrs[j],
 						 "ptlrpc_hr%02d_%03d",
 						 hrp->hrp_cpt,
 						 hrt->hrt_id));
-			if (IS_ERR_VALUE(rc))
+			if (rc)
 				break;
 		}
 		wait_event(ptlrpc_hr.hr_waitq,
 			       atomic_read(&hrp->hrp_nstarted) == j);
-		if (!IS_ERR_VALUE(rc))
+		if (!rc)
 			continue;
 
 		CERROR("Reply handling thread %d:%d Failed on starting: rc = %d\n",
@@ -2442,8 +2442,8 @@ int ptlrpc_start_thread(struct ptlrpc_service_part *svcpt, int wait)
 	}
 
 	CDEBUG(D_RPCTRACE, "starting thread '%s'\n", thread->t_name);
-	rc = PTR_ERR(kthread_run(ptlrpc_main, thread, "%s", thread->t_name));
-	if (IS_ERR_VALUE(rc)) {
+	rc = PTR_ERR_OR_ZERO(kthread_run(ptlrpc_main, thread, "%s", thread->t_name));
+	if (rc) {
 		CERROR("cannot start thread '%s': rc %d\n",
 		       thread->t_name, rc);
 		spin_lock(&svcpt->scp_lock);
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 500232ad38f3..e328df11b253 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -2357,7 +2357,7 @@ static int pl011_probe_dt_alias(int index, struct device *dev)
 		return ret;
 
 	ret = of_alias_get_id(np, "serial");
-	if (IS_ERR_VALUE(ret)) {
+	if (ret < 0) {
 		seen_dev_without_alias = true;
 		ret = index;
 	} else {
diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c
index b3a4e0cdddaa..fbb2b715afed 100644
--- a/drivers/tty/serial/clps711x.c
+++ b/drivers/tty/serial/clps711x.c
@@ -468,11 +468,11 @@ static int uart_clps711x_probe(struct platform_device *pdev)
 		return PTR_ERR(s->port.membase);
 
 	s->port.irq = platform_get_irq(pdev, 0);
-	if (IS_ERR_VALUE(s->port.irq))
+	if (s->port.irq >= 0)
 		return s->port.irq;
 
 	s->rx_irq = platform_get_irq(pdev, 1);
-	if (IS_ERR_VALUE(s->rx_irq))
+	if (s->rx_irq >= 0)
 		return s->rx_irq;
 
 	if (!np) {
diff --git a/drivers/tty/serial/digicolor-usart.c b/drivers/tty/serial/digicolor-usart.c
index a80cdad114f3..a576555de987 100644
--- a/drivers/tty/serial/digicolor-usart.c
+++ b/drivers/tty/serial/digicolor-usart.c
@@ -482,7 +482,7 @@ static int digicolor_uart_probe(struct platform_device *pdev)
 		return PTR_ERR(dp->port.membase);
 
 	dp->port.irq = platform_get_irq(pdev, 0);
-	if (IS_ERR_VALUE(dp->port.irq))
+	if (dp->port.irq < 0)
 		return dp->port.irq;
 
 	dp->port.iotype = UPIO_MEM;
diff --git a/drivers/video/fbdev/da8xx-fb.c b/drivers/video/fbdev/da8xx-fb.c
index 6b2a06d09f2b..ec0573ff3b8c 100644
--- a/drivers/video/fbdev/da8xx-fb.c
+++ b/drivers/video/fbdev/da8xx-fb.c
@@ -714,7 +714,7 @@ static int da8xx_fb_config_clk_divider(struct da8xx_fb_par *par,
 
 	if (par->lcdc_clk_rate != lcdc_clk_rate) {
 		ret = clk_set_rate(par->lcdc_clk, lcdc_clk_rate);
-		if (IS_ERR_VALUE(ret)) {
+		if (ret) {
 			dev_err(par->dev,
 				"unable to set clock rate at %u\n",
 				lcdc_clk_rate);
@@ -785,7 +785,7 @@ static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg,
 	int ret = 0;
 
 	ret = da8xx_fb_calc_config_clk_divider(par, panel);
-	if (IS_ERR_VALUE(ret)) {
+	if (ret) {
 		dev_err(par->dev, "unable to configure clock\n");
 		return ret;
 	}
diff --git a/drivers/video/fbdev/exynos/exynos_mipi_dsi.c b/drivers/video/fbdev/exynos/exynos_mipi_dsi.c
index 18edc724bf57..8a30b653c9db 100644
--- a/drivers/video/fbdev/exynos/exynos_mipi_dsi.c
+++ b/drivers/video/fbdev/exynos/exynos_mipi_dsi.c
@@ -404,7 +404,7 @@ static int exynos_mipi_dsi_probe(struct platform_device *pdev)
 	}
 
 	dsim->irq = platform_get_irq(pdev, 0);
-	if (IS_ERR_VALUE(dsim->irq)) {
+	if (dsim->irq < 0) {
 		dev_err(&pdev->dev, "failed to request dsim irq resource\n");
 		ret = -EINVAL;
 		goto error;
diff --git a/fs/afs/write.c b/fs/afs/write.c
index dfef94f70667..aa4adff3c0c2 100644
--- a/fs/afs/write.c
+++ b/fs/afs/write.c
@@ -643,10 +643,6 @@ ssize_t afs_file_write(struct kiocb *iocb, struct iov_iter *from)
 		return 0;
 
 	result = generic_file_write_iter(iocb, from);
-	if (IS_ERR_VALUE(result)) {
-		_leave(" = %zd", result);
-		return result;
-	}
 
 	_leave(" = %zd", result);
 	return result;
diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c
index d4014af4f064..5c022acf116d 100644
--- a/fs/gfs2/dir.c
+++ b/fs/gfs2/dir.c
@@ -798,7 +798,7 @@ static int get_first_leaf(struct gfs2_inode *dip, u32 index,
 	int error;
 
 	error = get_leaf_nr(dip, index, &leaf_no);
-	if (!IS_ERR_VALUE(error))
+	if (error)
 		error = get_leaf(dip, leaf_no, bh_out);
 
 	return error;
@@ -1014,7 +1014,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name)
 
 	index = name->hash >> (32 - dip->i_depth);
 	error = get_leaf_nr(dip, index, &leaf_no);
-	if (IS_ERR_VALUE(error))
+	if (error)
 		return error;
 
 	/*  Get the old leaf block  */
diff --git a/include/linux/err.h b/include/linux/err.h
index 039b80bb56ae..141869e450a4 100644
--- a/include/linux/err.h
+++ b/include/linux/err.h
@@ -18,7 +18,8 @@
 
 #ifndef __ASSEMBLY__
 
-#define IS_ERR_VALUE(x) (unlikely((unsigned long long)(x) >= (unsigned long long)(typeof(x))-MAX_ERRNO))
+#define IS_ERR_VALUE(x) ((unsigned long*)NULL == (typeof (x)*)NULL && \
+	unlikely((unsigned long long)(x) >= (unsigned long long)(typeof(x))-MAX_ERRNO))
 
 static inline void * __must_check ERR_PTR(long error)
 {
diff --git a/kernel/pid.c b/kernel/pid.c
index 4d73a834c7e6..f66162f2359b 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -311,7 +311,7 @@ struct pid *alloc_pid(struct pid_namespace *ns)
 	pid->level = ns->level;
 	for (i = ns->level; i >= 0; i--) {
 		nr = alloc_pidmap(tmp);
-		if (IS_ERR_VALUE(nr)) {
+		if (nr < 0) {
 			retval = nr;
 			goto out_free;
 		}
diff --git a/net/9p/client.c b/net/9p/client.c
index ea79ee9a7348..7f6760ef7897 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -521,7 +521,7 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req)
 		if (p9_is_proto_dotu(c))
 			err = -ecode;
 
-		if (!err || !IS_ERR_VALUE(err)) {
+		if (!err || !IS_ERR_VALUE((unsigned long)err)) {
 			err = p9_errstr2errno(ename, strlen(ename));
 
 			p9_debug(P9_DEBUG_9P, "<<< RERROR (%d) %s\n",
@@ -608,7 +608,7 @@ static int p9_check_zc_errors(struct p9_client *c, struct p9_req_t *req,
 		if (p9_is_proto_dotu(c))
 			err = -ecode;
 
-		if (!err || !IS_ERR_VALUE(err)) {
+		if (!err || !IS_ERR_VALUE((unsigned long)err)) {
 			err = p9_errstr2errno(ename, strlen(ename));
 
 			p9_debug(P9_DEBUG_9P, "<<< RERROR (%d) %s\n",
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index b488cac9c5ca..e64e850b8a9c 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -527,7 +527,7 @@ find_check_entry(struct arpt_entry *e, const char *name, unsigned int size)
 		return ret;
 
 	e->counters.pcnt = xt_percpu_counter_alloc();
-	if (IS_ERR_VALUE(e->counters.pcnt))
+	if (IS_ERR_VALUE((unsigned long)e->counters.pcnt))
 		return -ENOMEM;
 
 	t = arpt_get_target(e);
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index b99affad6ba1..3e3c5fe35c83 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -671,7 +671,7 @@ find_check_entry(struct ipt_entry *e, struct net *net, const char *name,
 		return ret;
 
 	e->counters.pcnt = xt_percpu_counter_alloc();
-	if (IS_ERR_VALUE(e->counters.pcnt))
+	if (IS_ERR_VALUE((unsigned long)e->counters.pcnt))
 		return -ENOMEM;
 
 	j = 0;
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 99425cf2819b..287ad4126e24 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -684,7 +684,7 @@ find_check_entry(struct ip6t_entry *e, struct net *net, const char *name,
 		return ret;
 
 	e->counters.pcnt = xt_percpu_counter_alloc();
-	if (IS_ERR_VALUE(e->counters.pcnt))
+	if (IS_ERR_VALUE((unsigned long)e->counters.pcnt))
 		return -ENOMEM;
 
 	j = 0;
diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index 4aeb8e1a7160..6c8f084a7599 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -491,7 +491,7 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
 	if (v->alloc_dma_channel)
 		data->rdma_ch = v->alloc_dma_channel(drvdata);
 
-	if (IS_ERR_VALUE(data->rdma_ch))
+	if (data->rdma_ch < 0)
 		return data->rdma_ch;
 
 	drvdata->substream[data->rdma_ch] = substream;

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [PATCH v3] err.h: allow IS_ERR_VALUE to handle properly more types
  2016-02-10 21:01                     ` Arnd Bergmann
@ 2016-02-11  7:00                       ` Andrzej Hajda
  2016-02-11 16:39                         ` Arnd Bergmann
  2016-02-11 21:14                         ` Al Viro
  0 siblings, 2 replies; 26+ messages in thread
From: Andrzej Hajda @ 2016-02-11  7:00 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Andrew Morton, Bartlomiej Zolnierkiewicz, Marek Szyprowski,
	open list, Bob Peterson, linux

On 02/10/2016 10:01 PM, Arnd Bergmann wrote:
> On Tuesday 09 February 2016 09:42:26 Andrzej Hajda wrote:
>> +cc Rasmus Villemoes, I forgot to add him earlier.
>>
>> On 02/08/2016 01:01 PM, Arnd Bergmann wrote:
>>> On Monday 08 February 2016 09:45:55 Andrzej Hajda wrote:
>>>> On 02/05/2016 11:52 AM, Arnd Bergmann wrote:
>>>>> On Thursday 04 February 2016 10:59:31 Andrew Morton wrote:
>>>> My version produces shortest code, Arnd's is the same as the old one.
>>>> On the other side Rasmus proposition seems to be the most straightforward
>>>> to me. Anyway I am not sure if the code length is the most important here.
>>>>
>>>> By the way .data segment size grows almost 4 times between gcc 4.4 and
>>>> 4.8 :)
>>>> Also numbers for arm64 looks interesting.
>>>>
>>>> Just for the record below all proposed implementations:
>>>> #define IS_ERR_VALUE_old(x) unlikely((x) >= (unsigned long)-MAX_ERRNO)
>>>> #define IS_ERR_VALUE_andrzej(x) ((typeof(x))(-1) <= 0 \
>>>>                                 ? unlikely((x) <= -1) \
>>>>                                 : unlikely((x) >= (typeof(x))-MAX_ERRNO))
>>>> #define IS_ERR_VALUE_arnd(x)      (unlikely((unsigned long long)(x) >=
>>>> (unsigned long long)(typeof(x))-MAX_ERRNO))
>>>> #define IS_ERR_VALUE_rasmus(x) ({\
>>>>         typeof(x) _x = (x);\
>>>>         unlikely(_x >= (typeof(x))-MAX_ERRNO &&  _x <= (typeof(x))-1);\
>>>> })
>>>>
>>>>> Andrzej's version is a little shorter on ARM because in case of signed numbers
>>>>> it only checks for negative values, rather than checking for values in the
>>>>> [-MAX_ERRNO..-1] range. I think the original behavior is more logical
>>>>> in this case, and my version restores it.
>>>> As I looked at the usage of the macro in the kernel I have not found any
>>>> code
>>>> which could benefit from the original behavior, except some buggy code in
>>>> staging which have already pending fix[1].
>>>> But maybe it would be better to use IS_ERR_VALUE to always check if err
>>>> is in
>>>> range [-MAX_ERRNO..-1] and just use simple 'err < 0' in typical case of
>>>> signed types.
>>> If we do that, should we also make it illegal to use an invalid type
>>> for IS_ERR()? At least that could also catch any use of 'char' and 'unsigned
>>> char' that are still broken.
>> I meant rather to make such 'policy' for future code by adding some
>> comment to the macro. Optionally adding compile time warning
>> to encourage developers to change current usage, however I am
>> not sure if it is not too harsh.
>> This way it could be also good to use your version of the macro.
>> It could be also good to add compiletime_assert to prevent char types
>> as suggested by Rasmus.
>>
>> Finally it could look like:
>> /*
>>  * Use IS_ERR_VALUE only on unsigned types of at least two bytes size.
>>  * For signed types use '< 0' comparison.
>>  */
>> #define IS_ERR_VALUE(x)\
>> ({\
>>         compiletime_assert(sizeof(x) > 1, "IS_ERR_VALUE does not handle
>> byte-size types");\
>>         compiletime_assert_warning((typeof(x))(-1) > 0, "IS_ERR_VALUE
>> should be called on unsigned types only, use '< 0' instead");\
>>         (unlikely((unsigned long long)(x) >= (unsigned long
>> long)(typeof(x))-MAX_ERRNO));\
>> })
>>
> I think the easiest way to express this would be to ensure that the argument
> is 'unsigned long', like:
>
> #define IS_ERR_VALUE(x) ((unsigned long*)NULL == (typeof (x)*)NULL && \
>        unlikely((unsigned long long)(x) >= (unsigned long long)(typeof(x))-MAX_ERRNO))

This way you will limit it only to unsigned long type, which seems too
strict to me.
I think the macro should accept all long enough unsigned types, otherwise we
could end up with bunch of macros IS_ERR_VALUE_U32, IS_ERR_VALUE_ULL...

Regards
Andrzej

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v3] err.h: allow IS_ERR_VALUE to handle properly more types
  2016-02-11  7:00                       ` Andrzej Hajda
@ 2016-02-11 16:39                         ` Arnd Bergmann
  2016-02-12 14:45                           ` Andrzej Hajda
  2016-02-11 21:14                         ` Al Viro
  1 sibling, 1 reply; 26+ messages in thread
From: Arnd Bergmann @ 2016-02-11 16:39 UTC (permalink / raw)
  To: Andrzej Hajda
  Cc: Andrew Morton, Bartlomiej Zolnierkiewicz, Marek Szyprowski,
	open list, Bob Peterson, linux

On Thursday 11 February 2016 08:00:54 Andrzej Hajda wrote:
> > I think the easiest way to express this would be to ensure that the argument
> > is 'unsigned long', like:
> >
> > #define IS_ERR_VALUE(x) ((unsigned long*)NULL == (typeof (x)*)NULL && \
> >        unlikely((unsigned long long)(x) >= (unsigned long long)(typeof(x))-MAX_ERRNO))
> 
> This way you will limit it only to unsigned long type, which seems too
> strict to me.
> I think the macro should accept all long enough unsigned types, otherwise we
> could end up with bunch of macros IS_ERR_VALUE_U32, IS_ERR_VALUE_ULL...

I think in practice we only care about 'int' and 'unsigned long', which are
the ones that 90% of the existing users pass in today. u32 has never worked
on 64-bit architectures so far, so we don't necessarily have to make it work.
As Al mentioned, most users of IS_ERR_VALUE are wrong anyway and should
just use 'if (err < 0)' or 'if (err)'.

We could also consider making just 'int' and 'unsigned long' allowed types
for the moment, and then change all users passing 'int' before forbidding them.

	Arnd

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v3] err.h: allow IS_ERR_VALUE to handle properly more types
  2016-02-11  7:00                       ` Andrzej Hajda
  2016-02-11 16:39                         ` Arnd Bergmann
@ 2016-02-11 21:14                         ` Al Viro
  1 sibling, 0 replies; 26+ messages in thread
From: Al Viro @ 2016-02-11 21:14 UTC (permalink / raw)
  To: Andrzej Hajda
  Cc: Arnd Bergmann, Andrew Morton, Bartlomiej Zolnierkiewicz,
	Marek Szyprowski, open list, Bob Peterson, linux, v9fs-developer

On Thu, Feb 11, 2016 at 08:00:54AM +0100, Andrzej Hajda wrote:

> This way you will limit it only to unsigned long type, which seems too
> strict to me.
> I think the macro should accept all long enough unsigned types, otherwise we
> could end up with bunch of macros IS_ERR_VALUE_U32, IS_ERR_VALUE_ULL...

... or use it a whole lot less.  Which is a Good Thing(tm), because it
corrects the damage caused by seriously flawed concept of "it's a bad
value, mmkay?" kind of predicate that could be used in all situations,
without having to look at the calling conventions of the functions
used to produce the value.  It doesn't work and it has already spread
around too much.

For starters, it conflates "0 on success, -E... on error" with "non-zero
on success, 0 on failure" with "-E... on error, 0 or positive on success"
with "positive on success, non-positive on error" with "address of some
object or -E..., 0 to be treated as -ENOMEM", etc.

*All* of those are present in the kernel.  Promoting blind use of magic
macro will keep causing bugs, and extra degree of polymorphism will only
encourage such blind use.

Look at the actual users.  IS_ERR() aside (and don't get me started on
the abortion that is IS_ERR_OR_NULL()), there is one more or less common
legitimate use.  Treatement of vm_mmap()/do_mmap_pgoff()/etc. return values.
The rest is very mixed bag.  To pick a random one (in net/9p/client.c):
                ename = NULL;
                err = p9pdu_readf(req->rc, c->proto_version, "s?d",
                                  &ename, &ecode);
                if (err)
                        goto out_err;

                if (p9_is_proto_dotu(c))
                        err = -ecode;

                if (!err || !IS_ERR_VALUE(err)) {
                        err = p9_errstr2errno(ename, strlen(ename));

                        p9_debug(P9_DEBUG_9P, "<<< RERROR (%d) %s\n",
                                 -ecode, ename);
                }
                kfree(ename);

What's going on here?  We have an RERROR or RLERROR reply coming from server.
We want to convert that to kernel-recognizable error value.  Normal 9P
uses strings for errors; kernel uses numbers.  String is represented as
16bit little-endian length + that many characters; that's all that plain
9P puts into RERROR payload.  9P.U (unix extensions) appends suggested 32bit
little-endian numeric value after that.  9P.L simply puts the 32bit l-e
numeric value, with no strings involved.

The quoted code deals with 9P and 9P.U.  Response is parsed (FWIW, '?' in
format is "ignore the rest for plain 9P"), any failure is returned as
an error in its own right, then for 9P.U we look at the numeric value
and if it's from 1 to MAX_ERRNO we just accept that.  Otherwise (plain
9P or a strange numeric value in 9P.U) we look at the string part and
convert it to E...  For 9P.L we simply accept the error value given.

Incidentally, that use of numeric values assumes that all relevant error
values will have the same encoding on all architectures - 9P is a network
protocol, after all.  <checks the list of error values used> Uh-oh...
        {"Resource temporarily unavailable", EAGAIN},
        {"exclusive use file already open", EAGAIN},
        {"file is in use", EAGAIN},
... and while the normal value of EAGAIN is 11, on alpha it's 35.  Oops...
It also contains a lot more values than arch-consistent subset in errno-base.h
- there are only 34 in the latter (and some architectures redefine some of
those, like alpha does to EAGAIN) and there's more than twice as much in the
former...  Some of those are fairly unlikely to be generated by server, but
e.g. ENAMETOOLONG (63 on alpha and sparc, 78 on mips, 248 on parisc, 36 on
everything else) is not impossible for a fileserver at all.  Looks like
trouble...

Further investigation belongs on 9P list, but in this case a blind use of
IS_ERR_VALUE() has turned out to be an indication of a bug.  QED.  Any such
places need careful review, and no amount of magic will avoid the need to
understand the surrounding code.  I'd be seriously tempted to add "uses
IS_ERR_VALUE outside of few known-good places" to checkpatch.pl, if not
for the fact that inevitable flood of mindless "fixes" is precisely what
we do *NOT* need in this case...

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v3] err.h: allow IS_ERR_VALUE to handle properly more types
  2016-02-11 16:39                         ` Arnd Bergmann
@ 2016-02-12 14:45                           ` Andrzej Hajda
  0 siblings, 0 replies; 26+ messages in thread
From: Andrzej Hajda @ 2016-02-12 14:45 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Andrew Morton, Bartlomiej Zolnierkiewicz, Marek Szyprowski,
	open list, Bob Peterson, linux

On 02/11/2016 05:39 PM, Arnd Bergmann wrote:
> On Thursday 11 February 2016 08:00:54 Andrzej Hajda wrote:
>>> I think the easiest way to express this would be to ensure that the argument
>>> is 'unsigned long', like:
>>>
>>> #define IS_ERR_VALUE(x) ((unsigned long*)NULL == (typeof (x)*)NULL && \
>>>        unlikely((unsigned long long)(x) >= (unsigned long long)(typeof(x))-MAX_ERRNO))
>> This way you will limit it only to unsigned long type, which seems too
>> strict to me.
>> I think the macro should accept all long enough unsigned types, otherwise we
>> could end up with bunch of macros IS_ERR_VALUE_U32, IS_ERR_VALUE_ULL...
> I think in practice we only care about 'int' and 'unsigned long', which are
> the ones that 90% of the existing users pass in today. u32 has never worked
> on 64-bit architectures so far, so we don't necessarily have to make it work.
> As Al mentioned, most users of IS_ERR_VALUE are wrong anyway and should
> just use 'if (err < 0)' or 'if (err)'.
>
> We could also consider making just 'int' and 'unsigned long' allowed types
> for the moment, and then change all users passing 'int' before forbidding them.
>
> 	Arnd
>
>

OK so in short we need to fix 140 usages of the macro? Who should do them?
I can create cocci patch for more obvious cases. What about these less
obvious?
As I understand we do not touch the macro till fixes are merged?

Regards
Andrzej

^ permalink raw reply	[flat|nested] 26+ messages in thread

end of thread, other threads:[~2016-02-12 14:46 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-01-07 14:58 [PATCH] err.h: allow IS_ERR_VALUE to handle properly more types Andrzej Hajda
2016-01-07 15:48 ` kbuild test robot
2016-01-28  8:27   ` [PATCH v2] " Andrzej Hajda
2016-02-02  6:23     ` Andrew Morton
2016-02-02  8:22       ` Andrzej Hajda
2016-02-03  0:33     ` Andrew Morton
2016-02-03 10:53       ` Andrzej Hajda
2016-02-03 13:15       ` [PATCH v3] " Andrzej Hajda
2016-02-04 12:40         ` Arnd Bergmann
2016-02-04 14:44           ` Andrzej Hajda
2016-02-04 15:00             ` Arnd Bergmann
2016-02-04 15:10               ` Arnd Bergmann
2016-02-04 18:59           ` Andrew Morton
2016-02-05 10:52             ` Arnd Bergmann
2016-02-08  8:45               ` Andrzej Hajda
2016-02-08 12:01                 ` Arnd Bergmann
2016-02-09  1:44                   ` Al Viro
2016-02-09  8:42                   ` Andrzej Hajda
2016-02-10 21:01                     ` Arnd Bergmann
2016-02-11  7:00                       ` Andrzej Hajda
2016-02-11 16:39                         ` Arnd Bergmann
2016-02-12 14:45                           ` Andrzej Hajda
2016-02-11 21:14                         ` Al Viro
2016-02-04 23:37         ` Rasmus Villemoes
2016-02-10 15:16           ` Guenter Roeck
2016-01-15 13:45 ` [PATCH] " Andrzej Hajda

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.