Eal:Error reading from file descriptor 33: Input/output error

created at 11-21-2021 views: 6

Problem Description

In the VMWARE virtual machine, after the 82545EM virtual network card is bound to igb_uio, run the dpdk program, and the dpdk program always has the following alarm information:

Eal:Error reading from file descriptor 33: Input/output error

The version of dpdk used is 16.04, and the program is l2fwd.

problem analysis

1. dpdk internal code
The code related to the error:

                        bytes_read = read(events[n].data.fd, &buf, bytes_read);
                        if (bytes_read < 0) {
                                if (errno == EINTR || errno == EWOULDBLOCK)
                                        continue;

                                RTE_LOG(ERR, EAL, "Error reading from file "
                                        "descriptor %d: %s\n",
                                        events[n].data.fd,
                                        strerror(errno));

The result printed by strerror is Input/output error, query the standard error value table, the definition of the related return value is as follows:

#define EIO              5      /* I/O error */

It indicates that the problem is that the error value of EIO is returned when reading from the uio file, so the problem is where is the return value of EIO returned from?

2. Code in the uio module
The code of the read callback function registered to the uio file in the uio module is as follows:

static ssize_t uio_read(struct file *filep, char __user *buf,
                        size_t count, loff_t *ppos)
{
        struct uio_listener *listener = filep->private_data;
        struct uio_device *idev = listener->dev;
        DECLARE_WAITQUEUE(wait, current);
        ssize_t retval;
        s32 event_count;

        if (!idev->info->irq)
                return -EIO;

The uio_read in the above code is the function finally called in the kernel when reading the /dev/uioX file. From the above function logic, it can be seen that when the value of idev->info->irq is `0`, the -EIO error will be returned.

So where is idev->info->irq initialized?

Research has confirmed that it is initialized in `igb_uio.c`.

3. Initialize the position of the **irq** field in the **uio_info** structure in **igb_uio.c**
The relevant code is as follows:

switch (igbuio_intr_mode_preferred) {
        case RTE_INTR_MODE_MSIX:
                /* Only 1 msi-x vector needed */
                msix_entry.entry = 0;
                if (pci_enable_msix(dev, &msix_entry, 1) == 0) {
                        dev_dbg(&dev->dev, "using MSI-X");
                        udev->info.irq = msix_entry.vector;
                        udev->mode = RTE_INTR_MODE_MSIX;
                        break;
                }
                /* fall back to INTX */
        case RTE_INTR_MODE_LEGACY:
                if (pci_intx_mask_supported(dev)) {
                        dev_dbg(&dev->dev, "using INTX");
                        udev->info.irq_flags = IRQF_SHARED;
                        udev->info.irq = dev->irq;
                        udev->mode = RTE_INTR_MODE_LEGACY;
                        break;
                }
                dev_notice(&dev->dev, "PCI INTX mask not supported\n");
                /* fall back to no IRQ */
        case RTE_INTR_MODE_NONE:
                udev->mode = RTE_INTR_MODE_NONE;
                udev->info.irq = 0;
                break;

        default:
                dev_err(&dev->dev, "invalid IRQ mode %u",
                        igbuio_intr_mode_preferred);
                err = -EINVAL;
                goto fail_release_iomem;
        }

The above process is first matched according to the interrupt mode set when the igb_uio module is loaded. The default value is RTE_INTR_MODE_MSIX. In the `VMWARE` environment, the 82545EM network card does not support msic and intx interrupts. In RTE_INTR_MODE_NONE case, the value of irq is set to 0, which causes dpdk to keep reporting errors when reading uio files through read.

solution

Although the 82545EM virtual network card in the VMWARE environment does not support msix and intx interrupts, the dpdk program can still run normally, indicating to a certain extent that the interrupt function is not used.

At the same time, analyzing the code to determine that only the `lsc` interrupt is relevant, and we have not enabled the lsc interrupt for the 82545EM network card.

Based on this fact, modify the igb_uio code and determine that the network card model is 82545EM, then execute the process in RTE_INTR_MODE_LEGACY.

The test determines that the problem is resolved after the modification.

Another optional modification is to not register the 82545EM NIC in the dpdk pmd driver to listen for uio interrupt events.

The specific modification method is as follows:

Determine the network card model in eth_em_dev_init. If it is 82545EM, set the fd field of intr_handle in interface pci_dev to -1.

created at:11-21-2021
edited at: 11-21-2021: