Невозможно создать пару очереди с 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);
2 ответа
ОБНОВЛЕНИЕ:
Основываясь на обсуждении в комментариях ниже, я предполагаю, что вы установили драйверы Mellanox OFED поверх вашего текущего дистрибутива. Глядя на источник драйверов ядра Mellanox OFED версии 3.1-1.0.3, я вижу, что они изменили расположение struct ib_qp_init_attr
добавив несколько полей. Я почти уверен, что ваша проблема в том, что вы собираете свой модуль на основе исходных заголовков ядра SLE 3.0.76-0.11, поэтому init_qpattr
структура вашего перехода к функции create 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, и, к сожалению, я не вижу очевидной ошибки.
Некоторые вещи, которые вы можете попробовать отладить
- Добавить параметр модуля
debug_level=1
кmlx4_core
модуль при загрузке. Обновите свой вопрос, используя все выходные данные инициализации драйвера (несколько строк о "Max CQEs:" и т. Д.) В драйвере mlx4 присутствует достаточное количество логики, которые зависят от параметров, возвращаемых fimrware во время инициализации, и этот вывод позволит мы видим, что это такое. - В этом отношении стоит проверить, обновлена ли ваша прошивка HCA - вы можете получить лучшие результаты с более новой прошивкой (хотя драйвер должен работать в любом случае, вы можете столкнуться с ошибкой в непроверенном коде драйвера из-за отсутствующей функции прошивки это вызывает другой путь кода).
- Попробуйте обновить код, чтобы увеличить эти параметры. Вы можете попробовать увеличить
max_send_sge
а такжеmax_recv_sge
до 2 и увеличитьmax_send_wr
а такжеmax_recv_wr
скажем, 32 или 128. (Попробуйте увеличить их по отдельности или в комбинации) - Если вы знаете, как включить функцию трассировки функций ( эта статья LWN полезна; я предполагаю, что старое ядро SLES обладает всеми необходимыми функциями), тогда включение трассировки для модулей mlx4_ib и mlx4_core и последующая загрузка вашего модуля будут отличными. Если вы обновите свой вопрос с помощью трассировки, то мы можем посмотреть, где происходит сбой операции создания QP - например, происходит ли сбой в
set_rq_size()
, Добраться доset_kernel_sq_size()
или терпит неудачу где-то еще?
Я думаю, что вы забыли зарегистрировать область памяти. Действия, которые необходимо выполнить перед созданием QP:
- Создание домена защиты
- Зарегистрировать область памяти
- Создание очередей завершения
и только потом создание QP.
Я не знаю, какое устройство и lib вы используете, но в Mellanox IB lib это:
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
}