Невозможно создать пару очередей с помощью ib_create_qp

Я пишу модуль ядра RDMA (InfiniBand).

До сих пор мне удавалось создавать домен защиты, очереди завершения для очередей отправки и получения.

Но всякий раз, когда я пытаюсь создать пару очереди, вызывая ib_create_qp, мне не удается создать пару очереди. Код, который я написал, показан ниже:

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/err.h>
#include "myClient.h"


struct workqueue_struct *myClient_workqueue;
struct ib_sa_client myClient_sa_client;
/*
static void myClient_add_one(struct ib_device *device);
static void myClient_remove_one(struct ib_device *device);
*/

struct ib_pd *mypd;
struct ib_cq *myrcvcq;
struct ib_cq *myClientsendcq;
struct ib_qp *myClientqp;

void myClient_ib_recvcompletion(struct ib_cq *cq)
{
    printk("A user-specified callback that is invoked when a completion event occurs on the CQ.\n");
}


void myClient_ib_sendcompletion(struct ib_cq *cq)
{
        printk("A user-specified callback that is invoked when a completion event occurs on the CQ.\n");
}
static void my_qp_event_handler(struct ib_event *myqpAsyncEvent, void *anyPointer)
{
        printk(KERN_INFO "Dummy affiliated asynchronous event occured function called \n");
}


static void myClient_add_one(struct ib_device *device)
{
    union ib_gid tmp_gid;
    int ret;
    int hcaport = 1;
    int result = -ENOMEM;
    u16 port1Pkey;
    struct ib_port_attr attr;

        ret = ib_query_port(device,hcaport,&attr);
        printk("ib query port result %d  \n", ret);

//  Creating the Protection Domain for RDMA
    mypd = ib_alloc_pd(device);

    if(IS_ERR(mypd)){
        printk(KERN_INFO "Failed to allocate PD\n");
        return;
    }
    else{
        printk(KERN_INFO "1Successfully allocated the PD\n");
        pdset = true;
    }

//  Creating the receive completion queue for RDMA
    myrcvcq = ib_create_cq(device,myClient_ib_recvcompletion,NULL,NULL,myClient_recvq_size,0);
        if(IS_ERR(myrcvcq)){
                pr_err("%s:%d error code for receive cq%d\n", __func__, __LINE__, PTR_ERR(myrcvcq));
                //printk("Error creating QP: %d \n",PTR_ERR(myClientqp));
        }
    else{
        printk("Recieve CQ successfully created in address: %x \n",myrcvcq);
    }

//  Creating the send completion queue for RDMA
    myClientsendcq = ib_create_cq(device,myClient_ib_sendcompletion, NULL, NULL,myClient_sendq_size,0 );
        if(IS_ERR(myClientsendcq)){
                pr_err("%s:%d scqerror code for send cq%d\n", __func__, __LINE__, PTR_ERR(myClientsendcq));
                //printk("Error creating QP: %d \n",PTR_ERR(myClientqp));
        }
        else{
                printk("1Send CQ successfully created in address: %x \n",myClientsendcq);
        }

//  Creating the queue pair
//      Creating the queue pair

        struct ib_qp_init_attr init_qpattr;

        memset(&init_qpattr,0,sizeof(init_qpattr));
        init_qpattr.event_handler = myClient_qp_event_handler;
        init_qpattr.cap.max_send_wr = 2;
        init_qpattr.cap.max_recv_wr = 2;
        init_qpattr.cap.max_recv_sge = 1;
        init_qpattr.cap.max_send_sge = 1;
        init_qpattr.sq_sig_type = IB_SIGNAL_ALL_WR;
        init_qpattr.qp_type = IB_QPT_UD;
        init_qpattr.send_cq = myClientsendcq;
        init_qpattr.recv_cq = myrcvcq;

        myClientqp = ib_create_qp(mypd,&init_qpattr);

        if(IS_ERR(myClientqp)){
                pr_err("%s:%d error code %d\n", __func__, __LINE__, PTR_ERR(myClientqp));
                //printk("Error creating QP: %d \n",PTR_ERR(myClientqp));
        }
        else{
                printk(KERN_INFO "1The queue pair is successfully created \n");
                qpcreated = true;
        }



}
static void myClient_remove_one(struct ib_device *device)
{
}

static struct ib_client my_client = {
        .name   = "myRDMAclient",
        .add    = myClient_add_one,
        .remove = myClient_remove_one
};


static int __init myRDMAclient_init(void)
{
    int ret;

    ret = ib_register_client(&my_client);
    if(ret){
        //printk(KERN_ALERT "KERN_ERR Failed to register IB client\n");
        goto err_sa;
    }
    printk(KERN_ALERT "lKERN_INFO Successfully registered myRDMAclient module \n");
    return 0;

err_sa:


    return ret;
}


module_init(myRDMAclient_init);

Здесь все запросы работают, кроме ib_create_qp(mypd,&init_qpattr);, который не может создать пару очереди.

Обновлено: зарегистрирована память перед созданием пары очереди. Но все же он показывает ошибку неверного аргумента (код ошибки -22) для ib_create_qp

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/err.h>
#include "myClient.h"


struct workqueue_struct *myClient_workqueue;
struct ib_sa_client myClient_sa_client;
/*
static void myClient_add_one(struct ib_device *device);
static void myClient_remove_one(struct ib_device *device);
*/

struct ib_pd *mypd;
struct ib_cq *myrcvcq;
struct ib_cq *myClientsendcq;
struct ib_qp *myClientqp;
struct ib_mr *mymr;

void myClient_ib_recvcompletion(struct ib_cq *cq)
{
    printk("A user-specified callback that is invoked when a completion event occurs on the CQ.\n");
}


void myClient_ib_sendcompletion(struct ib_cq *cq)
{
        printk("A user-specified callback that is invoked when a completion event occurs on the CQ.\n");
}
static void my_qp_event_handler(struct ib_event *myqpAsyncEvent, void *anyPointer)
{
        printk(KERN_INFO "Dummy affiliated asynchronous event occured function called \n");
}


static void myClient_add_one(struct ib_device *device)
{
    union ib_gid tmp_gid;
    int ret;
    int hcaport = 1;
    int result = -ENOMEM;
    u16 port1Pkey;
    struct ib_port_attr attr;

        ret = ib_query_port(device,hcaport,&attr);
        printk("ib query port result %d  \n", ret);

//  Creating the Protection Domain for RDMA
    mypd = ib_alloc_pd(device);

    if(IS_ERR(mypd)){
        printk(KERN_INFO "Failed to allocate PD\n");
        return;
    }
    else{
        printk(KERN_INFO "1Successfully allocated the PD\n");
        pdset = true;
    }
// Registering Memory
    mymr = ib_get_dma_mr(mypd,IB_ACCESS_LOCAL_WRITE | IB_ACCESS_REMOTE_READ| IB_ACCESS_REMOTE_WRITE);
    if(IS_ERR(mymr)){
            printk("failed to register memory :( %d \n",PTR_ERR(mymr));
    }else{
            printk(KERN_INFO "Successfully registered memory region :) \n");
    }
// End Registering Memory
//  Creating the receive completion queue for RDMA
    myrcvcq = ib_create_cq(device,myClient_ib_recvcompletion,NULL,NULL,myClient_recvq_size,0);
        if(IS_ERR(myrcvcq)){
                pr_err("%s:%d error code for receive cq%d\n", __func__, __LINE__, PTR_ERR(myrcvcq));
                //printk("Error creating QP: %d \n",PTR_ERR(myClientqp));
        }
    else{
        printk("Recieve CQ successfully created in address: %x \n",myrcvcq);
    }

//  Creating the send completion queue for RDMA
    myClientsendcq = ib_create_cq(device,myClient_ib_sendcompletion, NULL, NULL,myClient_sendq_size,0 );
        if(IS_ERR(myClientsendcq)){
                pr_err("%s:%d scqerror code for send cq%d\n", __func__, __LINE__, PTR_ERR(myClientsendcq));
                //printk("Error creating QP: %d \n",PTR_ERR(myClientqp));
        }
        else{
                printk("1Send CQ successfully created in address: %x \n",myClientsendcq);
        }

//  Creating the queue pair
//      Creating the queue pair

        struct ib_qp_init_attr init_qpattr;

        memset(&init_qpattr,0,sizeof(init_qpattr));
        init_qpattr.event_handler = myClient_qp_event_handler;
        init_qpattr.cap.max_send_wr = 2;
        init_qpattr.cap.max_recv_wr = 2;
        init_qpattr.cap.max_recv_sge = 1;
        init_qpattr.cap.max_send_sge = 1;
        init_qpattr.sq_sig_type = IB_SIGNAL_ALL_WR;
        init_qpattr.qp_type = IB_QPT_UD;
        init_qpattr.send_cq = myClientsendcq;
        init_qpattr.recv_cq = myrcvcq;

        myClientqp = ib_create_qp(mypd,&init_qpattr);

        if(IS_ERR(myClientqp)){
                pr_err("%s:%d error code %d\n", __func__, __LINE__, PTR_ERR(myClientqp));
                //printk("Error creating QP: %d \n",PTR_ERR(myClientqp));
        }
        else{
                printk(KERN_INFO "1The queue pair is successfully created \n");
                qpcreated = true;
        }



}
static void myClient_remove_one(struct ib_device *device)
{
}

static struct ib_client my_client = {
        .name   = "myRDMAclient",
        .add    = myClient_add_one,
        .remove = myClient_remove_one
};


static int __init myRDMAclient_init(void)
{
    int ret;

    ret = ib_register_client(&my_client);
    if(ret){
        //printk(KERN_ALERT "KERN_ERR Failed to register IB client\n");
        goto err_sa;
    }
    printk(KERN_ALERT "lKERN_INFO Successfully registered myRDMAclient module \n");
    return 0;

err_sa:


    return ret;
}


module_init(myRDMAclient_init);

person user3243499    schedule 14.01.2016    source источник
comment
Какое сообщение об ошибке выводится, когда IS_ERR(myClientqp) истинно?   -  person mhawke    schedule 14.01.2016
comment
Он говорит, что myClient_add_one: «номер строки» код ошибки -22   -  person user3243499    schedule 14.01.2016
comment
OK. так что означает код ошибки 22?   -  person mhawke    schedule 14.01.2016
comment
Есть ли файл в каталоге ядра Linux, где я могу найти значение этих кодов? Я хочу это, потому что разные веб-страницы упоминают для него разные значения.   -  person user3243499    schedule 14.01.2016
comment
22 - ЭИНВАЛ. Пишет, что один из переданных вами параметров недействителен. Я не вижу ничего явно неправильного в вашем коде; какую версию ядра и низкоуровневый драйвер IB (mlx4, mthca и т. д.) вы используете?   -  person Roland    schedule 14.01.2016
comment
версия ядра - 3.0.76-0.11, драйвер IB mlx4   -  person user3243499    schedule 14.01.2016
comment
еще один вопрос... какая архитектура? 32-битный x86, 64-битный x86, что-то еще?   -  person Roland    schedule 20.01.2016
comment
У вас есть IB, работающий над системой? Например, работает ли модуль ib_ipoib и создает ли интерфейс ib0, через который вы можете отправлять и получать трафик?   -  person Roland    schedule 21.01.2016
comment
Да Роланд. У меня уже установлен модуль ib_ipoib. Я вижу интерфейсы ib0 и ib1. ib0 и ib1 и связаны с интерфейсом bond0. И я могу пинговать другие системы ib_ipoib, используя эти интерфейсы.   -  person user3243499    schedule 21.01.2016
comment
@user3243499 user3243499 Если вам удалось это исправить, сообщите нам, как это сделать.   -  person JC1    schedule 15.03.2016


Ответы (2)


ОБНОВЛЕНИЕ:

Основываясь на обсуждении в комментариях ниже, я предполагаю, что вы установили драйверы Mellanox OFED поверх вашего текущего дистрибутива. Глядя на исходный код драйверов ядра Mellanox OFED 3.1-1.0.3, я вижу, что они изменили макет struct ib_qp_init_attr, добавив некоторые поля. Я почти уверен, что ваша проблема заключается в том, что вы создаете свой модуль на основе исходных заголовков ядра SLE 3.0.76-0.11, поэтому структура init_qpattr, которую вы передаете функции создания QP, не имеет значений, которые вы установили в правильном места.

Я не знаю, как вы установили новые драйверы вне дерева, поэтому я не могу точно сказать вам, как правильно собрать ваш модуль, но вы можете попробовать добавить что-то вроде

    init_qpattr.qpg_type = 0;

туда, где вы настроили структуру. (Я знаю, что вы уже memset все обнулили, но это гарантирует, что заголовки, с которыми вы строите, имеют новый член qpg_type для структуры. Я думаю, что это новое поле, добавленное OFED, которого нет в вашем исходном заголовки ядра, поэтому, если ваш модуль компилируется, значит, вы собираете правильные заголовки)

СТАРЫЙ ОТВЕТ:

Так что я подозреваю, что вы столкнулись с ошибкой в ​​драйвере mlx4, связанной с созданием таких маленьких QP (max_send_wr == max_recv_wr == 2 и max_send_sge == max_recv_sge == 1). Мне удалось найти исходный код используемого вами ядра 3.0.76-0.11, и, к сожалению, я не вижу какой-либо явной ошибки.

Некоторые вещи, которые вы могли бы попробовать помочь отладить

  1. Добавьте параметр модуля debug_level=1 в модуль mlx4_core при его загрузке. Обновите свой вопрос, указав все выходные данные инициализации драйвера (куча строк о «Max CQEs:» и т. д. В драйвере mlx4 есть достаточное количество логики, которая зависит от параметров, возвращаемых firrware во время инициализации, и этот вывод позволит мы видим, что это такое.
  2. В этом отношении стоит проверить, обновлена ​​ли ваша прошивка HCA — вы можете получить лучшие результаты с более новой прошивкой (хотя драйвер все равно должен работать, вы можете столкнуться с ошибкой в ​​​​непроверенном коде драйвера из-за отсутствующей функции прошивки. который запускает другой путь кода).
  3. Попробуйте обновить свой код, чтобы увеличить эти параметры. Вы можете попробовать увеличить max_send_sge и max_recv_sge до 2 и увеличить max_send_wr и max_recv_wr, скажем, до 32 или 128. (Попробуйте увеличить их по отдельности или в комбинации)
  4. Если вы знаете, как включить трассировщик функций (Эта статья LWN вам поможет ; Я предполагаю, что старое ядро ​​SLES имеет все необходимые функции), тогда было бы здорово включить трассировку для модулей mlx4_ib и mlx4_core, а затем загрузить ваш модуль. Если вы дополните свой вопрос трассировкой, то мы сможем посмотреть, где происходит сбой операции создания QP — например, сбой в set_rq_size(), переход к set_kernel_sq_size() или сбой где-то еще?
person Roland    schedule 21.01.2016
comment
Вы запускали этот код на ядре 3.0.76-0.11? Успешно ли создана пара очереди? Я думаю, что в моем ядре не была включена опция отладки, поэтому я не мог использовать ваш номер предложения. 1 и 4. Я проверил предложение номер 3, но оно также показало тот же код ошибки Invalid Argument -22. Предложение 2, над которым я работаю, требует некоторого времени для подтверждения. - person user3243499; 22.01.2016
comment
Я не зашел так далеко, чтобы установить SLES11, поэтому на самом деле я не пробовал ваш код. Я действительно озадачен тем, что IPoIB может успешно работать в вашей системе (и создавать QP), в то время как ваш код дает сбой. Драйвер IPoIB устанавливает несколько флагов при создании QP, которых нет у вас, но я не вижу, как это может иметь значение. Вы уверены, что строите свой модуль с правильными заголовками ядра? - person Roland; 22.01.2016
comment
Я просмотрел конфигурацию ядра SLES, и для AFAICT CONFIG_MLX4_DEBUG установлено значение «y», поэтому вы можете, по крайней мере, сделать № 1. Похоже, вы правы в том, что, к сожалению, трассировщик функционального графика не включен. Если вы можете пересобрать ядро, включение этого и/или простое добавление printks в драйвер mlx4 облегчит вам отладку. - person Roland; 23.01.2016
comment
Я использовал kprobe для отслеживания. Я обнаружил, что функция mlx4_ib_create_qp выполняется каждый раз, когда я загружаю свой модуль. Но внутри этой функции у меня есть еще одна функция check_qpg_attr. Но этот check_qpg_attr никогда не выполняется. (Я просто считал количество звонков с помощью kprobe). Важно отметить, что перед этим вызовом функции check_qpg_attr есть 4 блока if, каждый из которых возвращает -EINVAL (ошибка недопустимого аргумента). Дайте мне знать, если это полезная информация для вас - person user3243499; 23.01.2016
comment
Четыре блока if - if (mlx4_qp_flags & ~(MLX4_IB_QP_LSO | MLX4_IB_QP_CAP_CROSS_CHANNEL | MLX4_IB_QP_CAP_MANAGED_SEND | MLX4_IB_QP_CAP_MANAGED_RECV | MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK | MLX4_IB_SRIOV_TUNNEL_QP | MLX4_IB_SRIOV_SQP | MLX4_IB_QP_NETIF)) return ERR_PTR(-EINVAL); - person user3243499; 23.01.2016
comment
Но я не знаю значений этих символов перечисления. Если вы знаете, пожалуйста, дайте мне знать, чтобы я мог попробовать с ними и проверить еще раз. - person user3243499; 23.01.2016
comment
Вы выполняете прямую установку SLES11 SP3 или устанавливали драйверы OFED или Mellanox OFED? Не могли бы вы сообщить мне, как я могу получить тот же источник драйвера, на который вы ссылаетесь? Я смотрю на kernel.opensuse.org/cgit/kernel/plain/drivers/infiniband/hw/, и это не соответствует тому, что вы видите. - person Roland; 24.01.2016
comment
Давайте продолжим обсуждение в чате. - person Roland; 24.01.2016
comment
Да, установлены драйвера Mellanox OFED. И я не смог бы скомпилировать, если бы добавил init_qpattr.qpg_type = 0;. В этом случае он показывает, что ib_qp_init_aatr не имеет члена qpg_type. Обратите внимание, что ранее у меня была проблема с неизвестными символами версии для всех экспортированных символов IB при вставке. Поэтому я скопировал файл Module.symvers из /usr/src/ofa_kernel/default/Module.symvers. - person user3243499; 24.01.2016
comment
Тогда я мог бы успешно скомпилировать свой модуль и вставить его, если только этот ib_create_qp не вызывает ошибок. Пожалуйста, дайте мне знать, если эта информация была вам полезна - person user3243499; 24.01.2016
comment
Удалось ли вам успешно написать модуль ядра? - person S. Salman; 16.07.2016

Я думаю, вы забыли прописать область памяти. Действия, которые необходимо выполнить перед созданием QP:

  1. Создание домена защиты
  2. Зарегистрировать область памяти
  3. Создание очередей завершения

и только потом создавать QP.

Я не знаю, какое устройство и библиотеку вы используете, но в библиотеке Mellanox IB это:

char mr_buffer[REGION_SIZE];
//mypd its your protection domain that you allocated 
struct ibv_mr *mr = ibv_reg_mr(mypd , mr_buffer, REGION_SIZE, 0);
if (!mr) {
    //ERROR MSG
}
person Dor marcus    schedule 19.01.2016
comment
Какое типичное значение REGION_SIZE вы используете? - person user3243499; 19.01.2016
comment
Это абсолютно неправильно. Нет необходимости регистрировать MR перед созданием QP. - person Roland; 20.01.2016
comment
@Dor marcus: я внес изменения, поскольку ib_reg_mr отсутствует в ядре ib_verbs.h, а ib_reg_phys не реализован, я использовал ib_get_dma для регистрации. Он успешно зарегистрировал память. Однако я все еще получаю сообщение об ошибке -22 (для недопустимого аргумента) для ib_create_qp. Пожалуйста помоги. Спасибо - person user3243499; 21.01.2016