All of lore.kernel.org
 help / color / mirror / Atom feed
From: fengchengwen <fengchengwen@huawei.com>
To: "Morten Brørup" <mb@smartsharesystems.com>,
	dev@dpdk.org, "Dengdui Huang" <huangdengdui@huawei.com>
Cc: Stephen Hemminger <stephen@networkplumber.org>,
	Ferruh Yigit <ferruh.yigit@amd.com>,
	Tyler Retzlaff <roretzla@linux.microsoft.com>
Subject: Re: Strict aliasing problem with rte_eth_linkstatus_set()
Date: Thu, 11 Apr 2024 10:03:14 +0800	[thread overview]
Message-ID: <73d69caa-9779-2f51-5927-65e7b97154c0@huawei.com> (raw)
In-Reply-To: <98CBD80474FA8B44BF855DF32C47DC35E9F388@smartserver.smartshare.dk>

Hi Morten,

On 2024/4/10 18:30, Morten Brørup wrote:
>> From: fengchengwen [mailto:fengchengwen@huawei.com]
>> Sent: Wednesday, 10 April 2024 11.34
>>
>> Hi All,
>>
>> We have a problem introduced by a compiler upgrade (from gcc10 to gcc12.3),
>> we've done some
>> research but haven't been able to figure out why. We'd like the community's
>> help.
>>
>> Environment:
>> 1. Source: DPDK 23.11
>> 2. GCC: 12.3.1 [1]
>> 3. Compiled with target kunpeng SoC (ARM64)
>> 4. Run on kunpeng SoC
>>
>>
>> Problem & Debug:
>> 1. We found the hns3 driver fails to update the link status. The corresponding
>> function is
>> hns3_update_linkstatus_and_event [2], and we found the rte_eth_linkstatus_set
>> [3] always return zero.
>> 2. After disassembly the hns3_update_linkstatus_and_event, and found
>> rte_eth_linkstatus_set's
>> rte_atomic_exchange_explicit return to xzr register (which is zero register):
>>  1239fec:       3900f3e0        strb    w0, [sp, #60]
>>  1239ff0:       9101a041        add     x1, x2, #0x68      ---x2 seem not the
>> variable new_link
>>  1239ff4:       f8ff8022        swpal   xzr, x2, [x1]      ---this instr
>> corresponding rte_atomic_exchange_explicit,
>>                                                               it will place
>> the resut in xzr which always zero,
>>                                                               and this will
>> lead to rte_eth_linkstatus_set return 0.
>>  1239ff8:       3940f3e0        ldrb    w0, [sp, #60]
>>  1239ffc:       d3609c41        ubfx    x1, x2, #32, #8
>>  123a000:       4a010000        eor     w0, w0, w1
>>  123a004:       36100080        tbz     w0, #2, 123a014
>> <hns3_update_linkstatus_and_event+0xd4>
>> 3. We checked other "ret = rte_eth_linkstatus_set" calls, and can't find
>> similar problem.
>> 4. After reading a lot of documents, we preliminarily think that the problem
>> is caused by -fstrict-aliasing
>> (which was enabled default with O2 or O3), if compiled with -fno-strict-
>> aliasing, then this problem don't
>> exist. We guest this maybe strict-aliasing's bug which only happened in our
>> function.
>> 5. We also try to use union to avoid such aliasing in rte_eth_linkstatus_set,
>> we changed the struct
>> rte_eth_link define, and it works:
>>   -__extension__
>>   -struct __rte_aligned(8) rte_eth_link { /**< aligned for atomic64 read/write
>> */
>>   -       uint32_t link_speed;        /**< RTE_ETH_SPEED_NUM_ */
>>   -       uint16_t link_duplex  : 1;  /**< RTE_ETH_LINK_[HALF/FULL]_DUPLEX */
>>   -       uint16_t link_autoneg : 1;  /**< RTE_ETH_LINK_[AUTONEG/FIXED] */
>>   -       uint16_t link_status  : 1;  /**< RTE_ETH_LINK_[DOWN/UP] */
>>   +struct rte_eth_link { /**< aligned for atomic64 read/write */
>>   +       union {
>>   +               uint64_t val64;
>>   +               struct {
>>   +                       uint32_t link_speed;        /**< RTE_ETH_SPEED_NUM_
>> */
>>   +                       uint16_t link_duplex  : 1;  /**<
>> RTE_ETH_LINK_[HALF/FULL]_DUPLEX */
>>   +                       uint16_t link_autoneg : 1;  /**<
>> RTE_ETH_LINK_[AUTONEG/FIXED] */
>>   +                       uint16_t link_status  : 1;  /**<
>> RTE_ETH_LINK_[DOWN/UP] */
>>   +               };
>>   +       };
>>   };
>> the corresponding rte_eth_linkstatus_set:
>>   @@ -1674,18 +1674,13 @@ static inline int
>>    rte_eth_linkstatus_set(struct rte_eth_dev *dev,
>>                          const struct rte_eth_link *new_link)
>>    {
>>   -       RTE_ATOMIC(uint64_t) *dev_link = (uint64_t __rte_atomic *)&(dev-
>>> data->dev_link);
>>   -       union {
>>   -               uint64_t val64;
>>   -               struct rte_eth_link link;
>>   -       } orig;
>>   -
>>   -       RTE_BUILD_BUG_ON(sizeof(*new_link) != sizeof(uint64_t));
>>   +       struct rte_eth_link old_link;
>>
>>   -       orig.val64 = rte_atomic_exchange_explicit(dev_link, *(const uint64_t
>> *)new_link,
>>   +       old_link.val64 = rte_atomic_exchange_explicit(&dev->data-
>>> dev_link.val64,
>>   +                                       new_link->val64,
>>                                           rte_memory_order_seq_cst);
>>
>>   -       return (orig.link.link_status == new_link->link_status) ? -1 : 0;
>>   +       return (old_link.link_status == new_link->link_status) ? -1 : 0;
>>    }
>> 6. BTW: the linux kernel enabled "-fno-strict-aliasing" default, please see
>> [4] for more.
>>
> 
> Thank you for the detailed analysis.
> Looking at the GCC documentation for -fstrict-aliasing supports your conclusion.
> 
> Just out of curiosity:
> Does building with -Wstrict-aliasing=3 or -Wstrict-aliasing=1 provide any useful information?

There are no any useful information with -Wstrict-aliasing=3

But for -Wstrict-aliasing=1, there are plenty of warnings, below is rte_eth_linkstatus_set:

In file included from ../../dpdk/lib/ethdev/rte_ethdev.c:32:
../../dpdk/lib/ethdev/ethdev_driver.h: In function ‘rte_eth_linkstatus_set’:
../../dpdk/lib/ethdev/ethdev_driver.h:1677:67: warning: dereferencing type-punned pointer might break strict-aliasing rules [-Wstrict-aliasing]
 1677 |         RTE_ATOMIC(uint64_t) *dev_link = (uint64_t __rte_atomic *)&(dev->data->dev_link);
      |                                                                   ^~~~~~~~~~~~~~~~~~~~~~
../../dpdk/lib/ethdev/ethdev_driver.h:1685:9: warning: dereferencing type-punned pointer might break strict-aliasing rules [-Wstrict-aliasing]
 1685 |         orig.val64 = rte_atomic_exchange_explicit(dev_link, *(const uint64_t *)new_link,
      |         ^~~~

Note: above without apply my fix (use union).

> And are the any differences in the strict-aliasing warnings without/with your fix?

After apply my fix (use union), with enabled -Wstrict-aliasing=1, there are no strict-aliasing warnings related to rte_eth_linkstatus_set.

Thanks

> 
>>
>> Last: We think there are two ways to solve this problem.
>> 1. Add the compilation option '-fno-strict-aliasing' for hold DPDK project.
>> 2. Use union to avoid such aliasing in rte_eth_linkstatus_set (please see
>> above).
>> PS: We prefer first way.
>>
>> Hope for more discuess.
>>
>> Thanks
> 
> Unfortunately, DPDK uses a lot of type casting where other methods would be formally more correct.
> I fear that you only found one of potentially many more bugs like this.
> Fixing this generally would be great, but probably not realistic.
> 
> I prefer correctness over performance, and thus am in favor of adding -fno-strict-aliasing project wide.
> 
> Performance can be improved by adding more hints and attributes to functions and parameters, e.g. rte_memcpy() could be:
> __attribute__((access(write_only, 1, 3), access(read_only, 2, 3)))
> static void *
> rte_memcpy(void * restrict dst, const void * restrict src, size_t n);
> 
> Instead of just:
> static void *
> rte_memcpy(void * dst, const void * src, size_t n);
> 
> 
>>
>>
>> [1] https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads/12-3-
>> rel1
>> [2] void
>> hns3_update_linkstatus_and_event(struct hns3_hw *hw, bool query)
>> {
>> 	struct rte_eth_dev *dev = &rte_eth_devices[hw->data->port_id];
>> 	struct rte_eth_link new_link;
>> 	int ret;
>>
>> 	if (query)
>> 		hns3_update_port_link_info(dev);
>>
>> 	memset(&new_link, 0, sizeof(new_link));
>> 	hns3_setup_linkstatus(dev, &new_link);
>>
>> 	ret = rte_eth_linkstatus_set(dev, &new_link);
>> 	if (ret == 0 && dev->data->dev_conf.intr_conf.lsc != 0)
>> 		hns3_start_report_lse(dev);
>> }
>> [3] static inline int
>> rte_eth_linkstatus_set(struct rte_eth_dev *dev,
>> 		       const struct rte_eth_link *new_link)
>> {
>> 	RTE_ATOMIC(uint64_t) *dev_link = (uint64_t __rte_atomic *)&(dev->data-
>>> dev_link);
>> 	union {
>> 		uint64_t val64;
>> 		struct rte_eth_link link;
>> 	} orig;
>>
>> 	RTE_BUILD_BUG_ON(sizeof(*new_link) != sizeof(uint64_t));
>>
>> 	orig.val64 = rte_atomic_exchange_explicit(dev_link, *(const uint64_t
>> *)new_link,
>> 					rte_memory_order_seq_cst);
>>
>> 	return (orig.link.link_status == new_link->link_status) ? -1 : 0;
>> }
>> [4] https://lore.kernel.org/all/b3itcd$2bi$1@penguin.transmeta.com/

  parent reply	other threads:[~2024-04-11  2:03 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-04-10  9:33 Strict aliasing problem with rte_eth_linkstatus_set() fengchengwen
2024-04-10 10:30 ` Morten Brørup
2024-04-10 15:57   ` Ferruh Yigit
2024-04-11  2:03   ` fengchengwen [this message]
2024-04-10 15:27 ` Stephen Hemminger
2024-04-10 15:58   ` Ferruh Yigit
2024-04-10 17:54   ` Morten Brørup
2024-04-10 19:58     ` Tyler Retzlaff
2024-04-11  3:20       ` fengchengwen
2024-04-10 21:18     ` Stephen Hemminger

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=73d69caa-9779-2f51-5927-65e7b97154c0@huawei.com \
    --to=fengchengwen@huawei.com \
    --cc=dev@dpdk.org \
    --cc=ferruh.yigit@amd.com \
    --cc=huangdengdui@huawei.com \
    --cc=mb@smartsharesystems.com \
    --cc=roretzla@linux.microsoft.com \
    --cc=stephen@networkplumber.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.