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)
{
read_unlock_bh(tmp_lock); //スピンロックを解除する
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);
<最後にstruct file_operations構造体を定義すると、proc_my_test_openがカーネルに渡され、proc_createが呼び出されてprocディレクトリが作成されました。コードは次のとおりです。
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です。
そのうちの一つ。 -g:-lと同じですが、所有者をリストしません。 -G、 - no-group:グループ情報の表示を抑制します。 -i、 - inode:各ファイルのiノード番号をリストします
Ubuntuは良いLinuxオペレーティングシステムですが、それをインストールしたばかりの初心者にとっては、Ubuntuを使ってネットワークに接続する方法は非常に困難です。 Ubuntuの下であなた自
1. Javaをインストールします(ここではインストールディレクトリのビットを/usr /localとします) 32ビット:http://download.oracle.com/otn-pub/j