既存の dm-linear、dm-snapshot、dm-cache などを参照して、デバイス マッパー ターゲットを実装しようとしています。私の実装では、特定のセクター範囲で読み取り/変更/書き込み操作を実行する必要があります。デバイス マッパーはブロック レイヤーと直接対話するため、メモリ内のセクターを読み取り、バッファーを変更して別のセクター範囲に書き戻すために使用するデータ構造/関数がわかりません。アプリケーション レベルには syscall があり、その下には vfs_read/vfs_write があります。デバイスマッパーレイヤーに似たものはありますか? 私はここで非常に長い間立ち往生しています。どんな助けでも大歓迎です。
1 に答える
注: 3.14 以降の API はわずかに変更されているため、私の回答はカーネル バージョン < 3.14 に関連しています。
カーネルでは、特定のセクターを で読み書きしstruct bioます。この構造体は、すべてのブロック レベルの I/O に使用されます。包括的なドキュメントはカーネルとlwnにあります。これらは、この構造のいくつかの最も重要なメンバーです。
bio->bi_sector- ブロック I/O 要求の最初のセクターbio->bi_size- I/O リクエストのサイズbio->bi_bdev- 読み書きするデバイスbio->bi_end_io- リクエストの最後にカーネルが呼び出すコールバック
デバイス マッパー ターゲットで行うことは、マップの着信bioです。デバイス マッパー ターゲットを作成するときは、少なくとも 2 つのコールバックを指定します:ctrとmap。たとえば、最も単純なデバイス マッパー ターゲットdm-zeroは、そのコールバックを次のように宣言します。
static struct target_type zero_target = {
.name = "zero",
.version = {1, 1, 0},
.module = THIS_MODULE,
.ctr = zero_ctr,
.map = zero_map,
};
mapはキー コールバックです。これは、すべてのデバイス マッパー ターゲットの心臓部です。map着信を受信bioし、それで何でもできます。たとえば、dm-linear はbio、事前に定義されたオフセットによってすべての着信のセクターをシフトするだけです。コードを参照してください。
static sector_t linear_map_sector(struct dm_target *ti, sector_t bi_sector)
{
struct linear_c *lc = ti->private;
return lc->start + dm_target_offset(ti, bi_sector);
}
static void linear_map_bio(struct dm_target *ti, struct bio *bio)
{
struct linear_c *lc = ti->private;
bio->bi_bdev = lc->dev->bdev;
if (bio_sectors(bio))
bio->bi_sector = linear_map_sector(ti, bio->bi_sector);
}
static int linear_map(struct dm_target *ti, struct bio *bio)
{
linear_map_bio(ti, bio);
return DM_MAPIO_REMAPPED;
}
マップはポインターを受け取るためbio、そのポインターの下で値を変更できます。それだけです。
これが、I/O 要求をマップする方法です。独自のリクエストを作成したい場合は、割り当てbio、そのセクター、デバイス、サイズを埋め、コールバックを終了し、読み書きするバッファを追加する必要があります。基本的に、それはほんの数ステップです:
- bio_alloc を呼び出して bio を割り当てます。
- セット
bio->bi_bdev,bio->bi_sector,bio->bi_size,bio->bi_end_io - 経由でページを追加します
bio_add_page。 - コールし
submit_bioます。 bio->bi_end_ioコールバックで結果とエラーを処理する
例は、関数の dm-cryptターゲットにありcrypt_alloc_bufferます。