1

私は Linux aio (libaio) の初心者であり、経験豊富な誰かが私を助けてくれることを願っています。

PCI デバイスからシステム RAM への高速 DMA を実行するシステムがあります。次に、libaio を使用して DMA アドレス空間から直接データをディスクに書き込みたいと考えています。現在、DMA に使用されるメモリは、「memmap」カーネル ブート コマンドを使用してブート時に予約されます。

私のアプリケーションでは、メモリは mmap を使用して仮想ユーザー空間アドレス ポインターにマップされます。これをバッファーとして io_prep_pwrite() 呼び出しに渡すことができるはずです。ただし、これを行うと、書き込みが成功しないようです。要求が io_getevents でリープされると、「res」フィールドにエラー コード -22 が含まれ、「Bad Address」として出力されます。

ただし、以前にマップされたメモリ位置からアプリケーションによって割り当てられた新しいバッファーに memcpy を実行し、io_prep_pwrite の呼び出しでこのローカル バッファーへのポインターを使用すると、要求は正常に機能し、データはディスクに書き込まれます。問題は、memcpy を実行すると、データをディスクにストリーミングする必要がある速度のボトルネックが生じ、DMA レートについていけないことです。

書き込み要求が機能するために最初にメモリをコピーする必要がある理由がわかりません。以下の問題を説明するために最小限の例を作成しました。bufBaseLoc はマップされたアドレスで、localBuffer はデータのコピー先のアドレスです。次の行を実行する必要はありません。

memcpy(localBuffer, bufBaseLoc, WRITE_SIZE);

...または localBuffer をまったく持っています。「IOCB の準備」セクションで使用したいもの:

io_prep_pwrite(iocb, fid, bufBaseLoc, WRITE_SIZE, 0);

...しかし、うまくいきません。しかし、単なるコピーであるローカル バッファは機能します。

誰かが理由について何か洞察を持っていますか? どんな助けでも大歓迎です。

ありがとう、

#include <cstdio>
#include <string>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <libaio.h>

#define WRITE_SIZE 0x80000              //4MB buffer
#define DMA_BASE_ADDRESS 0x780000000    //Physical address of memory reserved at boot

//Reaping callback
void writeCallback(io_context_t ctx, struct iocb *iocb, long res, long res2)
{
  //Res is number of bytes written by the request.  It should match the requested IO size.  If negative it is an error code
  if(res != (long)iocb->u.c.nbytes)
  {
    fprintf(stderr, "WRITE_ERROR: %s\n", strerror(-res));
  }
  else
  {
    fprintf(stderr, "Success\n");
  }
}

int main()
{ 
  //Initialize Kernel AIO
  io_context_t ctx = 0;
  io_queue_init(256, &ctx);

  //Open /dev/mem and map physical address to userspace
  int fdmem = open("/dev/mem", O_RDWR);
  void *bufBaseLoc = mmap(NULL, WRITE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fdmem, DMA_BASE_ADDRESS);

  //Set memory here for test (normally done be DMA)
  memset(bufBaseLoc, 1, WRITE_SIZE);

  //Initialize Local Memory Buffer (DON’T WANT TO HAVE TO DO THIS)
  uint8_t* localBuffer;
  posix_memalign((void**)&localBuffer, 4096, WRITE_SIZE);
  memset(localBuffer, 1, WRITE_SIZE);

  //Open/Allocate file on disk
  std::string filename = "tmpData.dat";
  int fid = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_DIRECT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
  posix_fallocate(fid, 0, WRITE_SIZE);

  //Copy from DMA buffer to local process buffer (THIS IS THE COPY I WANT TO AVOID)
  memcpy(localBuffer, bufBaseLoc, WRITE_SIZE);

  //Prepare IOCB
  struct iocb *iocbs[1];
  struct iocb *iocb = (struct iocb*) malloc(sizeof (struct iocb));
  io_prep_pwrite(iocb, fid, localBuffer, WRITE_SIZE, 0);      //<--THIS WORKS (but is not what I want to do)
  //io_prep_pwrite(iocb, fid, bufBaseLoc, WRITE_SIZE, 0);  //<--THIS DOES NOT WORK (but is what I want to do)
  io_set_callback(iocb, writeCallback);
  iocbs[0] = iocb;

  //Send Request
  int res = io_submit(ctx, 1, iocbs);
  if (res !=1)
  {
    fprintf(stderr, "IO_SUBMIT_ERROR: %s\n", strerror(-res));
  }

  //Reap Request
  struct io_event events[1];
  size_t ret = io_getevents(ctx, 1, 1, events, 0);
  if (ret==1)
  {
    io_callback_t cb=(io_callback_t)events[0].data;
    struct iocb *iocb_e = events[0].obj;
    cb(ctx, iocb_e, events[0].res, events[0].res2);
  }

}
4

1 に答える 1

1

元のバッファが整列されていない可能性があります。

libAIO がディスクに書き込むバッファはすべて (約 4K になると思います) 整列する必要があります。を使用して一時バッファをposix_memalign割り当てると、正しく配置されて割り当てられます。つまり、書き込みが成功します。元の予約済みバッファが整列されていない場合、問題が発生する可能性があります。

整列された割り当てでその初期バッファーを割り当てようとすることができれば、問題を解決できます。

于 2018-07-24T06:47:30.080 に答える