7

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);ここでは、キュー ペアの作成に失敗した を除いて、すべてのクエリが機能します。

更新: キュー ペアを作成する前にメモリを登録しました。それでも、ib_create_qp の無効な引数エラー (エラー コード -22) が表示されます。

#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);
4

2 に答える 2

3

更新

以下のコメントの議論に基づいて、現在のディストリビューションの上に 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 によって追加された新しいフィールドだと思います、したがって、モジュールがコンパイルされる場合は、正しいヘッダーに対してビルドしています)

古い答え:

max_send_wr == max_recv_wr == 2そのため、このような小さな QP (および)の作成に関連する mlx4 ドライバーのバグに遭遇していると思われますmax_send_sge == max_recv_sge == 1。あなたが使用している 3.0.76-0.11 カーネルのソースを見つけることができましたが、残念ながら明らかなバグは見当たりません。

これをデバッグするのに役立ついくつかのこと

  1. モジュールをロードするときdebug_level=1に、モジュールにモジュール パラメーターを追加します。mlx4_coreドライバーの初期化からのすべての出力 (「Max CQEs:」などに関する一連の行) で質問を更新します。mlx4 ドライバーには、初期化中に fimrware によって返されるパラメーターに依存するかなりの量のロジックがあり、この出力により、それらが何であるかがわかります。
  2. さらに言えば、HCA ファームウェアが最新であるかどうかを確認する価値があります。新しいファームウェアを使用すると、より良い結果が得られる可能性があります (ドライバーはとにかく動作するはずですが、ファームウェア機能がないために未テストのドライバー コードでバグが発生している可能性があります)。別のコード パスをトリガーします)。
  3. コードを更新して、これらのパラメーターを増やしてみてください。max_send_sgeandmax_recv_sgeを 2 に増やして、 max_send_wrandを増やして、たとえば 32 または 128 にすることができますmax_recv_wr(これらを個別に、または組み合わせて増やしてみてください)。
  4. 関数トレーサーを有効にする方法を知っている場合 (この LWN 記事は役に立ちます。古い SLES カーネルには必要な機能がすべて備わっていると思います)、mlx4_ib および mlx4_core モジュールのトレースを有効にしてから、モジュールをロードするとよいでしょう。トレースを使用して質問を更新すると、QP 作成操作がどこで失敗しset_rq_size()ているset_kernel_sq_size()かを確認できます。
于 2016-01-21T22:10:30.957 に答える
-1

メモリ領域の登録を忘れていたようです。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
}
于 2016-01-19T09:07:22.967 に答える