Linuxでは、procファイルシステムを介してユーザー状態とカーネル状態の相互作用またはカーネルの微調整を行うことは比較的簡単で効果的な方法です。最近、プロジェクトのニーズにより、procを通してカーネルモジュールのデータをユーザーモードに出力し、seq_fileを学ぶ機会を得る必要があります。ここで簡単な記録を作りなさい、そして間違った場所は批判を歓迎する。 seq_fileを使用するには、#include
が必要です。さて、ナンセンスな話はしないで、始めましょう、^ _ ^。私たちのカーネルモジュールの1つに、反復可能なデータ構造(リンクリスト、配列など)に格納されたデータのセットがあり、それらをprocを通してユーザー状態に出力し、catなどを通してそれらを表示したいとします。やり方簡単にするために、データのリンクリストがあるとすると、リンクリストの先頭はlist_headという変数で指し示され、それ自体は読み書き可能なスピンロックで保護されています。リンクリストノードの構造は次のとおりです。
構造ノード{
構造ノード* next;
int num;
};
struct node * list_head; //チェインテーブルヘッダ
DEFINE_RWLOCK(list_lock); //読み書きスピンロックを定義して初期化します。
seq_fileは、反復のための関数ポインタのセットを定義します。これはC ++の順方向反復子のように機能しますが、ノード情報を出力するためのshowというメンバを持ちます。この関数ポインタのセットは、次のようにstruct seq_operationsという構造体で宣言されています。
struct seq_operations { void(* stop)(struct seq_file * m、void * v); void *(* next)(struct seq_file * m、void * v、loff_t * pos); Br> int(* show)(struct seq_file * m、void * v); }; startはリソースの取得と初期化作業を行うことができます、かなりc ++のコンストラクタです。ロールとその戻り値は、最初の呼び出しと次の呼び出しの2番目のパラメーターとして渡され、そのたびにnextとshowが呼び出され、戻り値がNULLの場合はstart、直接呼び出しがstopの場合はshowとなりません。次へ出力するヘッダがある場合は、SEQ_START_TOKENカーネルに戻ることができます: #define SEQ_START_TOKEN((void *)1) nextの戻り値はshowおよびnextの呼び出しとして使用されます。 nextの2番目の引数(つまりv)が渡され、nextがNULLを返すとstopが呼び出されます。 stopの役割は、C ++クラスのデストラクタの役割と似ており、リソースのクリーンアップと戻り操作を担当します。 show関数は正しく0を返し、エラーは対応するエラーコードを返します。 出力情報は一度にカーネルによって割り当てられたバッファよりも大きいので(具体的な理由、次回seq_readや他の関数の実装について書くときなど)、start、show、nextのようになります。 、stopは複数回呼び出すことができます。これは、startとnextの3番目のパラメーターposを区別するために必要です。そのため、それらの呼び出しの順序は、開始 - >表示 - >次 - >表示 - >次 - >表示 - > ... - >次へ - >停止と記述することができます。 次のようにすることもできます(開始停止は複数回呼び出されます):start-> show-> next-> show-> next-> ...-> next-> > stop-> start-> show-> next ...-> next->停止します。これらの反復関数は、この例では次のように定義できます。 static void * my_start(struct seq_file * m、l loff_t * pos) { int i = 1; struct node * tmp_entry; read_lock_bh(list_lock); //読み書きスピンロックを取得します。 if(* pos == 0){ return SEQ_START_TOKEN; } for(tmp_entry = list_head; tmp_entry!= NULL; tmp_entry = tmp-entry-> next){ if(i == * pos) return tmp_entry; ++ i; } return NULL; } static void my_stop(struct seq_file * m、void * v) { seq_printf(m、 " \\ n \\ n -------------データ情報の終わり---------------------------";); } static void * my_next(struct seq_file * m、void * v、loff_t * pos) { ++ * Pos; return(SEQ_START_TOKEN == v)?list_head:((struct node *)v) - &g t; next; } static int my_show(struct seq_file * m、void * v) { struct node * tmp_entry; static int line_count = 0; if(SEQ_START_TOKEN == v){ seq_printf(m、" \\ n \\ n ----------) ---データ情報の開始--------------------------- \\ n \\ n"); } else {< Br> tmp_entry =(struct node *)v; seq_file(m、"%d"、tmp_entry-> num); if(++ line_count = = 10){//1行で10個のデータが出力されます。 seq_printf(m、" \\ n"); line_count = 0; } } return 0; } 次に、struct seq_operationsを次のように定義します。 static const struct seq_operations my_seq_ops = { .start = my_start、 .next = my_next、 .stop = my_stop、 .show = my_show、 }; この時点で、my_seq_opsのアドレスをカーネルに出力する関数も定義する必要があります。次のように、 static int proc_my_test_open((struct inode * inode、struct file * file)) { return seq_open(file、& my_seq_ops); static const struct file_operations my_file_ops = { .owner = THIS_MODULE、 .open = proc_my_test_open、 .read = seq_read、< Br> .llseek = seq_lseek、 .release = seq_release、 }; my_file_opsproc_create(" my_test"、0、NULL、& my_file_ops); 実際には、単純な出力のために、あなたは単にshow関数を定義することができます、そしてここで我々のseq_openの代わりにsingle_openを通して、この方法は比較的簡単です、特定の方法はgoogleです。
read_unlock_bh(tmp_lock); //スピンロックを解除する
<最後にstruct file_operations構造体を定義すると、proc_my_test_openがカーネルに渡され、proc_createが呼び出されてprocディレクトリが作成されました。コードは次のとおりです。
そのうちの一つ。 -g:-lと同じですが、所有者をリストしません。 -G、 - no-group:グループ情報の表示を抑制します。 -i、 - inode:各ファイルのiノード番号をリストします
Ubuntuは良いLinuxオペレーティングシステムですが、それをインストールしたばかりの初心者にとっては、Ubuntuを使ってネットワークに接続する方法は非常に困難です。 Ubuntuの下であなた自
1. Javaをインストールします(ここではインストールディレクトリのビットを/usr /localとします) 32ビット:http://download.oracle.com/otn-pub/j