[Etherlab-dev] Patch for non-recursive ec_master_calc_topology

SOUQUIERES JEROME jerome.souquieres at solystic.com
Fri Aug 21 15:11:22 CEST 2020


Hi,


I encountered a crash in the ethercat driver when using a bus with a large number of modules (~500). The ec_master_calc_topology_rec() recursive function sometimes exhausts the kernel stack and crashes.


I fixed this issue by reimplementing this function in a non-recursive way. As I'm afraid I'm not familiar with mercurial, I will post the code directly here, with two variants:

- one for the main repository

- one for the gavinl patchset



/******* for main repository *************************************************************/

/** Calculates the bus topology.
 */

typedef struct
{
   ec_slave_t *slave;
   unsigned int port_index;
} topology_stack_t;

void ec_master_calc_topology(
        ec_master_t *master /**< EtherCAT master. */
        )
{
    unsigned int slave_position = 0;
    ec_slave_t *next_slave;
    void* stack_base;
    topology_stack_t* stack_top;

    static const unsigned int next_table[EC_MAX_PORTS] = {
        3, 2, 0, 1
    };

    if (master->slave_count == 0)
        return;

    if (!(stack_base = kmalloc(sizeof(topology_stack_t) * master->slave_count, GFP_KERNEL))) {
        EC_MASTER_ERR(master, "Failed to allocate stack.\n");
        return;
    }
    stack_top = (topology_stack_t*)stack_base;

    // first slave
    stack_top->slave = master->slaves;
    stack_top->port_index = 3;
    ++stack_top;

    while ( stack_top != (topology_stack_t*)stack_base )
    {
        topology_stack_t* cur = stack_top - 1;

        if (cur->port_index == 0) {
            --stack_top;
            continue;
        }

        if (!cur->slave->ports[cur->port_index].link.loop_closed) {
            slave_position += 1;
            if (slave_position >= master->slave_count) {
                kfree(stack_base);
                EC_MASTER_ERR(master, "Failed to calculate bus topology.\n");
                return;
            }

            next_slave = master->slaves + slave_position;
            cur->slave->ports[cur->port_index].next_slave = next_slave;
            next_slave->ports[0].next_slave = cur->slave;

            stack_top->slave = next_slave;
            stack_top->port_index = 3;
            ++stack_top;
        }

        cur->port_index = next_table[cur->port_index];
    }

    kfree(stack_base);
}



/******* for gavinl patchset *************************************************************/

/** Calculates the bus topology.
 */

typedef struct
{
   ec_slave_t *slave;
   unsigned int port_index;
} topology_stack_t;

void ec_master_calc_topology(
        ec_master_t *master /**< EtherCAT master. */
        )
{
    unsigned int slave_position = 0;
    ec_slave_t *next_slave;
    void* stack_base;
    topology_stack_t* stack_top;

    static const unsigned int next_table[EC_MAX_PORTS] = {
        3, 2, 0, 1
    };

    if (master->slave_count == 0)
        return;

    if (!(stack_base = kmalloc(sizeof(topology_stack_t) * master->slave_count, GFP_KERNEL))) {
        EC_MASTER_ERR(master, "Failed to allocate stack.\n");
        return;
    }
    stack_top = (topology_stack_t*)stack_base;

    // first slave
    stack_top->slave = master->slaves;
    stack_top->port_index = next_table[stack_top->slave->upstream_port];
    ++stack_top;

    while ( stack_top != (topology_stack_t*)stack_base )
    {
        topology_stack_t* cur = stack_top - 1;

        if (cur->port_index == cur->slave->upstream_port) {
            --stack_top;
            continue;
        }

        if (!cur->slave->ports[cur->port_index].link.loop_closed) {
            slave_position += 1;
            if (slave_position >= master->slave_count) {
                kfree(stack_base);
                EC_MASTER_ERR(master, "Failed to calculate bus topology.\n");
                return;
            }

            next_slave = master->slaves + slave_position;
            cur->slave->ports[cur->port_index].next_slave = next_slave;
            next_slave->ports[next_slave->upstream_port].next_slave = cur->slave;

            stack_top->slave = next_slave;
            stack_top->port_index = next_table[stack_top->slave->upstream_port];
            ++stack_top;
        }

        cur->port_index = next_table[cur->port_index];
    }

    kfree(stack_base);
}



[Disclaimer Solystic]
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.etherlab.org/pipermail/etherlab-dev/attachments/20200821/58a97505/attachment.htm>


More information about the Etherlab-dev mailing list