ioviter構造体--翻訳
6044 ワード
はじめに本文はオリジナルです.知識点や理解上の問題があるかもしれません.切磋琢磨と交流を歓迎します. ^_^
私はcephファイルシステムを分析しています.perform_writeインターフェース時に、その中にstruct iovが流れます.iter*iが読めなくて、struct iovに対してiter*iは分析を行い、このインターフェースは以下の通りである.
以下の内容は翻訳されたもので、原文の内容はリンクされています.
https://lwn.net/Articles/625077/
1.構造体の紹介
カーネルの中で最も一般的なタスクの一つは、ユーザ状態のキャッシュデータを処理することである.したがって、このような頻繁にエラーが発生するカーネルコードは、通常、バグを引き起こすか、またはセキュリティ・ホールを引き起こす可能性がある.しかし、カーネルには原語が含まれていて、「iovuuiter」と呼ばれています.しかしiov_iter構造はしばしばカーネル管理またはファイルシステム層に用いられる.しかしここ数年、このようなデータ構造はカーネルの他のモジュールにも使われてきました.この構造体はまだ文書を出力していないので、文書を説明する役割を果たしています.
ioviterの概念は最新のものではなく、ニコピグが2007年に発表した2.6.24バージョンのカーネルに初めて追加したものです.しかし、過去1年間、人々はこのアプリを拡張するために努力してきました.カーネルの多くのモジュールで使われています.例えば、3.19リリースのバージョンは、ネットワークサブシステムモジュールにコンパイルされていることが見られます.
ioviter構造は実際には、iovec構造を遍歴するためのシーズムレータであり、また、Ovecは、次の図のようにファイルに定義されている.
● iovoffset:構造体のiovポインタによって指し示す最初のiovec構造体におけるデータの最初のバイトのオフセットを記述する.
● count:iovec配列が指すデータの個数はcountに格納されます.
● nr_regs:iovec構造体の個数はnr_に保存されています.segs中
これらのフィールドはいずれもキャッシュの更新とともに更新されます.
2. struct ioviterの使用
使う前に、iov_を初期化しなければなりません.iter構造体は、一つ(充填された)iovec構造体を含むために使用される:
なお、これらの呼び出しは、転送データに対応するバッファ領域の増加により、iov_をインクリメントする.iter構造体のアドレスの変化.言い換えれば、サブジェネレータのiov_.offset、count、nr_segsとiovフィールドは必要に応じて変更されます.したがって、copy_を二回呼び出します.fromiter()は、ユーザ空間から2つの連続領域をコピーする.また、シーケンサを実行する命令は、iovec配列の基本アドレスを覚えなければなりません. struct iovec*iovアドレス値が変化します.
データはpageページの構造とサブジェネレータのiov_にあります.iter間でコピーするインターフェースは以下の通りです.
原子コンテキストで動作するコードは、以下の方法でユーザ空間からデータを取得することを試みることができる.
ユーザ空間バッファをカーネルにマッピングする必要がある場合、以下の関数が使用できます.
任意のデータを移動せずにローズマリーで進みます.
3.拡張部分
上に表示されている構造体のiov_iterの定義は,カーネルで実際に見つけられたものとは完全に一致しない.本当の構造はiov配列の単一フィールドだけではなく、以下のようになっています(3.18で)
3.19バージョン
3.19内核はiov_に対する可能性がある.iterコードは大量書き換えを行い、上の関数によって実現される大量の冗長コードを減らすことを目的としています.再構成されたコードはより短く精悍であるが、その代償は多くのマクロ定義を導入している.
3.19内のソースコードの中で、次のインターフェースからディエゼルが生成されます.
最後に、いくつかの関数を追加して、ネットワーク問題の発生を処理するのを助けることができます.例えば、バッファデータをコピーして、チェックするためにchocksumを生成します.
現在、iov_iter構造体は、ユーザ状態バッファデータの処理がもたらす複雑さを遮断するための方法を徐々に実行している.このロジックは現在約7年間存在しています.iterの構造体験は徐々により多くの関数インターフェースを生み出し、カーネル開発者に使用されるようになった.
ioviterインタフェース
私はcephファイルシステムを分析しています.perform_writeインターフェース時に、その中にstruct iovが流れます.iter*iが読めなくて、struct iovに対してiter*iは分析を行い、このインターフェースは以下の通りである.
ssize_t generic_perform_write(struct file *file, struct iov_iter *i, loff_t pos)
「記憶技術原理分析」では、構造体iovecの由来について述べました.概括すると、私たちが通常使用するシステムはread/writeを呼び出してファイルの読み取りや書き込みに用います.例えば、readはデータを1つのユーザ状態バッファエリアに読み取り、readvはデータを複数のユーザ状態バッファエリアに読み出すために、この2つのsysscallに対応するためにデータ構造iovecを導入しました.iterはまたiovecに対する反復である.ですから、iov_を使いますiter構造体の本質は、ユーザ状態バッファデータとページキャッシュとのマッピング関係の処理を支援するために使用される.以下の内容は翻訳されたもので、原文の内容はリンクされています.
https://lwn.net/Articles/625077/
1.構造体の紹介
カーネルの中で最も一般的なタスクの一つは、ユーザ状態のキャッシュデータを処理することである.したがって、このような頻繁にエラーが発生するカーネルコードは、通常、バグを引き起こすか、またはセキュリティ・ホールを引き起こす可能性がある.しかし、カーネルには原語が含まれていて、「iovuuiter」と呼ばれています.しかしiov_iter構造はしばしばカーネル管理またはファイルシステム層に用いられる.しかしここ数年、このようなデータ構造はカーネルの他のモジュールにも使われてきました.この構造体はまだ文書を出力していないので、文書を説明する役割を果たしています.
ioviterの概念は最新のものではなく、ニコピグが2007年に発表した2.6.24バージョンのカーネルに初めて追加したものです.しかし、過去1年間、人々はこのアプリを拡張するために努力してきました.カーネルの多くのモジュールで使われています.例えば、3.19リリースのバージョンは、ネットワークサブシステムモジュールにコンパイルされていることが見られます.
ioviter構造は実際には、iovec構造を遍歴するためのシーズムレータであり、また、Ovecは、次の図のようにファイルに定義されている.
struct iovec
{
void __user *iov_base; //
__kernel_size_t iov_len; //
};
この構造は、posixインターフェースで定義されたユーザ空間iovec構造体と整合し、readv()システム呼び出しとともに使用される.名前の「vec」部分の説明のように、iovec構造は配列の形で出現する傾向がある.全体として、iovecはバッファ領域を記述し、このバッファ領域は物理的および仮想メモリに分散する可能性がある.実際のioviter構造体定義は、ファイルにあります.下図のように、struct iov_iter {
int type;
size_t iov_offset;
size_t count;
const struct iovec *iov; /* SIMPLIFIED - see below */
unsigned long nr_segs;
};
● タイプを説明します.これはビットで、読みと書きを含めて、読みと書きはデータを読んで、ディエゼルから書きます.したがって、データ処理の方向は、サブコマンダー自体を指すのではなく、データ処理の他の部分、すなわち、読み出し操作によって作成されたiov_である.iterは書き込みされます● iovoffset:構造体のiovポインタによって指し示す最初のiovec構造体におけるデータの最初のバイトのオフセットを記述する.
● count:iovec配列が指すデータの個数はcountに格納されます.
● nr_regs:iovec構造体の個数はnr_に保存されています.segs中
これらのフィールドはいずれもキャッシュの更新とともに更新されます.
2. struct ioviterの使用
使う前に、iov_を初期化しなければなりません.iter構造体は、一つ(充填された)iovec構造体を含むために使用される:
void iov_iter_init(struct iov_iter *i, int direction,
const struct iovec *iov, unsigned long nr_segs,
size_t count);
以下のいずれかの方法を使って、iov_にいます.iterディケンサ構造体とユーザ状態空間の間のデータのコピー: size_t copy_to_iter(void *addr, size_t bytes, struct iov_iter *i);
size_t copy_from_iter(void *addr, size_t bytes, struct iov_iter *i);
ここのネーミングはちょっと乱れているかもしれません.コツが分かります.copy_を呼び出しますto_iter()は、バイトデータをaddrアドレスが指すバッファからバイト数がbytesであるデータをバイトポインタが指すユーザ空間バッファアドレスにコピーします.だからcopy_to_iter()はcopy_と考えられます.to_user()の一つの変体は、単なるバッファアドレスではなく、ローズマリー構造体を受け入れています.類似して、copy_fromiter()はユーザ空間バッファからaddrにデータをコピーする.関数実行の戻り値とcopy_to_user()は、コピーされていないバイトの個数と一致しているままである.なお、これらの呼び出しは、転送データに対応するバッファ領域の増加により、iov_をインクリメントする.iter構造体のアドレスの変化.言い換えれば、サブジェネレータのiov_.offset、count、nr_segsとiovフィールドは必要に応じて変更されます.したがって、copy_を二回呼び出します.fromiter()は、ユーザ空間から2つの連続領域をコピーする.また、シーケンサを実行する命令は、iovec配列の基本アドレスを覚えなければなりません. struct iovec*iovアドレス値が変化します.
データはpageページの構造とサブジェネレータのiov_にあります.iter間でコピーするインターフェースは以下の通りです.
size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes,
struct iov_iter *i);
size_t copy_page_from_iter(struct page *page, size_t offset, size_t bytes,
struct iov_iter *i);
注意:提供された単一のページだけがデータにコピーされたり、中からデータがコピーされたりするので、これらの関数はページ境界を越えるデータを処理する必要がありません.原子コンテキストで動作するコードは、以下の方法でユーザ空間からデータを取得することを試みることができる.
size_t iov_iter_copy_from_user_atomic(struct page *page, struct iov_iter *i, unsigned long offset, size_t bytes);
このコピーは原子モードで行われるため、RAMにデータが存在している場合にのみ成功する.したがって、使用者はより高い失敗率のために準備しなければならない.ユーザ空間バッファをカーネルにマッピングする必要がある場合、以下の関数が使用できます.
ssize_t iov_iter_get_pages(struct iov_iter *i, struct page **pages,
size_t maxsize, unsigned maxpages, size_t *start);
ssize_t iov_iter_get_pages_alloc(struct iov_iter *i, struct page ***pages,
size_t maxsize, size_t *start);
この二つの関数はまずget_を呼び出します.アメリカ.pages_fastは、ページを取得し、ページキャッシュに格納する.それらの違いはiov_にあります.iter_ゲットするPages()はページキャッシュ配列が調整者自身で割り当てられています.iter_ゲットするpages_alloc()はカーネル自身で割り当てられます.この場合、調整者自身がkmallocまたはvmalloc関数を介して申請したページキャッシュ配列は、関数が戻ると、配列はkvfreeを呼び出してリリースしなければならない.任意のデータを移動せずにローズマリーで進みます.
void iov_iter_advance(struct iov_iter *i, size_t size);
ローズマリーが指すバッファは、以下の方法でクリアできます.size_t iov_iter_zero(size_t bytes, struct iov_iter *i);
サブジェネレータの構造体に関する情報は以下の関数から取得できます.size_t iov_iter_single_seg_count(const struct iov_iter *i);
int iov_iter_npages(const struct iov_iter *i, int maxpages);
size_t iov_length(const struct iovec *iov, unsigned long nr_segs);
iov_を呼び出しますiter_シングルス.seg_count()はバッファエリアの第一段のデータの長さを返します.ioviter_npages()は、シーケンサにバッファが占めるページ数を返します.length()は全データ長を返します.また、この関数はiovec構造におけるlenフィールドを信頼するので、注意して使用しなければなりません.このデータがユーザ空間から来た場合、カーネル中の整数オーバーフローを引き起こす可能性がある.3.拡張部分
上に表示されている構造体のiov_iterの定義は,カーネルで実際に見つけられたものとは完全に一致しない.本当の構造はiov配列の単一フィールドだけではなく、以下のようになっています(3.18で)
union {
const struct iovec *iov;
const struct bio_vec *bvec;
};
言い換えれば、iov_iter構造体には,ブロックデバイス層で使用されるBIO構造体も含まれている.そのため、このサブジェネレータの構造体では、iter_uが見られます.bvecのような構造体が存在する.このローズマリー構造体が作成されると、上記のすべての関数が呼び出されます.現在、カーネルではビオベースのローズマリーを使用することが少なく、swapとsplice()コードの中でしか見つけられません.3.19バージョン
3.19内核はiov_に対する可能性がある.iterコードは大量書き換えを行い、上の関数によって実現される大量の冗長コードを減らすことを目的としています.再構成されたコードはより短く精悍であるが、その代償は多くのマクロ定義を導入している.
3.19内のソースコードの中で、次のインターフェースからディエゼルが生成されます.
void iov_iter_kvec(struct iov_iter *i, int direction,
const struct kvec *iov, unsigned long nr_segs,
size_t count);
この場合には、上のunionタイプに新たなkvecフィールドを追加する必要がある.最後に、いくつかの関数を追加して、ネットワーク問題の発生を処理するのを助けることができます.例えば、バッファデータをコピーして、チェックするためにchocksumを生成します.
現在、iov_iter構造体は、ユーザ状態バッファデータの処理がもたらす複雑さを遮断するための方法を徐々に実行している.このロジックは現在約7年間存在しています.iterの構造体験は徐々により多くの関数インターフェースを生み出し、カーネル開発者に使用されるようになった.
ioviterインタフェース