既存の 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
ます。