スタックポインタの値
こんにちは。LKHSです。
自分はレジスタの中では何といっても esp (スタックポインタ)が一番好きなのですが(?)、プログラム中で esp の値を確認したい時があります。
![]() |
|
日本発のリナックス企業、ミラクル・リナックスで奮闘する社員のブログです。
| 日 | 月 | 火 | 水 | 木 | 金 | 土 |
|---|---|---|---|---|---|---|
| 1 | ||||||
| 2 | 3 | 4 | 5 | 6 | 7 | 8 |
| 9 | 10 | 11 | 12 | 13 | 14 | 15 |
| 16 | 17 | 18 | 19 | 20 | 21 | 22 |
| 23 | 24 | 25 | 26 | 27 | 28 | 29 |
| 30 | 31 |
こんにちは。LKHSです。
自分はレジスタの中では何といっても esp (スタックポインタ)が一番好きなのですが(?)、プログラム中で esp の値を確認したい時があります。
うち(ペンギン飼育係)のBLOG"vi系ユーザのカーネルコード参照環境"をみて、自分もviユーザなので、ちょっと調べてみましたところ、
MiracleLinuxのブログ(コアテクの路地)にいっぱいviの技(?!)が紹介されていました。
みんなバラバラで、散らばっているので、今日は、今まで紹介されたvi技を集めてみました。
コアテクの路地”マクロ機能(キーボードマクロ)"
viを使ったマクロ。使ったことがないぁ。
コアテクの路地”秀丸になりたーい”
taglist.vimとgrep.vimの紹介。taglist.vimは自分も使っています。
コアテクの路地"vim: edコマンドを使う"
vi使って置換したい時は、ここ。
コアテクの路地"vim: 見えない文字を見えるようにする。"
これ、知らなかったです。。使ってみようっと。
コアテクの路地”vimでマルチウィンド"
これ、知っていると便利。
コアテクの路地"vim のファイル文字コード指定"
これまた、便利ですね。
コアテクの路地"タグジャンプ"
ソース見るときには必須ですね。
Emacsもおぼえようかな。
世のカーネルハッカーの皆さんは、カーネルのソースツリーを読み書きするのにそれぞれ独自の最適化済環境を構築しているだろうと想像するのですが、ふりかえって私はといえば、Linuxカーネルを読むようになってもうすぐ3年が経とうというのに全くもって環境らしい環境さえ整えていません。
代官山のバッカスです。前回に引き続き、ローカライゼーションのお話です。
いきなりですが ATOK で「ろーからいぜーしょん」と入力して変換すると「ロー、辛いぜー、ション」と出てきます。「ション」とは何なのか気になるところですが、ローカリゼーションは一発で変換できるので、この表記の方が本当は正しいようです。さらに余談ですが ATOK は Alpha To Kanji の略ということになっています。これが実は「阿波(A) 徳島 (TO) かな漢字 (K)」の略語だという説があります(浮川さん、ごめんなさい)。
さてソフトウェアの国際化を果たしてヨーロッパに進出したアメリカ企業は、まずはメジャーな言語に翻訳をすることになります。最小の労力で最大のマーケットをカバーするためには、とりあえずドイツ語、フランス語、イタリー語、スペイン語あたりからスタートしたものです。これらを FIGS(フィッグス)と略しました。
頭文字を並べて略すのは洋の東西を問いません。「水兵リーベ(周期律表)」や「妻子異国に(円周率)」、「鮒一羽二羽(自然対数)」と同じです。経済成長著しい国のリスト、BRICs(Brazil、Russia、India、China)とか、それを追い上げる VISTA(Vietnam、Indonesia、South Africa、Turkey、Argentine)なんてのもあります。
FIGS とは実はうまい略語で、英語の「not worth a fig(何の役にもたたない)」という言い方を連想させるのです。その複数型でメジャーな翻訳言語を表すなんて、いいセンスじゃないですか。
その後ポルトガル語を加えて P-FIGS(ピーフィッグス)になりますが、「ピー」という音は英語圏の人間にとって「ション」と同じ語感があるので定着しませんでした。ポルトガル語版の実際のマーケットはイベリア半島(ヨーロッパ、イベリコ豚の産地)じゃなくてブラジル(南米)だっ!、と BFIGS に改名して定着した次第です。
中南米は大航海時代にポルトガルやスペインに植民地化されたので、これらの言葉が定着したわけですが、時を経るにしたがって言葉は分化してきました。ポルトガル語は Iberian Portuguese と Brazilian Portuguese の二つに分かれ、「ブラジル語」という言い方すらされるようになっています。津軽言葉と熊本言葉が、津軽語と熊本語という名前を持つようになったようなものです。
単語レベルでもヨーロッパと中南米は違いまして、computer のことを中南米では「コンピュータ」、ヨーロッパでは「オルテナドール (計算機)」と呼びます。Mouse が中南米は「マウス」、ヨーロッパでは「ラトン (鼠)」になります。もっとも最近は逆輸入で、ヨーロッパでも「コンピュータ」「マウス」と呼ばれるようになりつつあるようにも聞いています。
余談その3:アメリカにボカ・ラトンという地名があります。あれは料理の「サルティン・ボッカ (口に飛び込む)」の「ボカ=口」と「ラトン」で、鼠の口の形をした湾からきている、という説を聞いたことがありますが、真偽や如何。
そうこうしているうちに、国際化は儲かるぞ、ということになりまして、アメリカのソフトウェア会社はこぞって売上に占める海外の比率を競うようになりました。国内依存ではジリ貧になるぞ、ということで国際化に遅れたソフトウェア会社の株価は、どんどん下がっていったものです。
当然 BFIGS の次はどこだ、という議論になります。他の国は一国あたりの市場規模がそれほど大きくなく、モトが取れるかどうかで散々もめたものです。データの改竄/捏造や地元の誘致 (翻訳してくれたら沢山売れるよ〜)、脅迫(翻訳がないと撤退せざるを得ない)も絡んで、一時は収拾のつかない騒ぎになったものです。
結局落ち着いたのは、ddnsf、chpr、GrTu の11カ国語でした。ddnsf はオランダ (Dutch)、デンマーク、ノルウェー、スエーデン、フィンランドの北欧諸国。chpr は「チッパー」と発音してチェコ、ハンガリー、ポーランド、ロシアの東欧圏。GrTu はギリシア語とトルコ語です(文字処理に一ひねり必要なので別扱)。
(ちなみに ddnsf とかけて、4軸ディーゼル機関車のデータベースファイル、と解いた貴方、相当ニッチです。C57 と DC8 とかけて、何と解きます?)
BFIGS は全部大文字ですが、ddnsf を始めとする言語群は小文字です。某社内では最優先で全部翻訳をする言語をグループ1,次のレベルをグループ2、特別のことがない限り翻訳をしない言語をグループ3と呼んでいました。B(P)FIGS と CJKT (中日韓台) がグループ1で大文字。ddnsf 以下はグループ2で小文字の扱いです。GrTu や Th(タイ語)は G2 と G3 の間を行ったり来たりしていましたね。
かつてバッカスは翻訳言語の一覧をさらさらと言って感心されたものですが、実は略語を唱えていたにすぎません。円周率を35桁 (妻子異国に婿、産後厄なく産児み社に、虫燦々闇に鳴く頃にや) 唱えるのと同じことです。何の役にもたちません。
そろそろ酔いが回ってきたのでバッカスは寝みます。次回もしつこく国際化。今度はいよいよダブルバイト。それではまた。
前回実機まで確保して、このお題もようやく軌道に乗り始めたと思ったのも束の間、その後またもや時間が取れず、さらに昨夜、首を傷めたりなどしたもので(あんまり関係ないかも)、全くネタがありません。こんな時は諦めて、カーネルのソースツリーで grep 遊びなどをしてみましょうか。。。
お疲れさまです。代官山のバッカスです。バッカスの Mac Book(クロ♪)は Core 2 Duo 搭載以前に買ったので、最近は 15インチの Mac Book Pro(クロ♪じゃなくてプロ)に触手が動いています。Leopard までにはお金を貯めて64ビットの世界を満喫したいと思っています。
さて、バッカスはこの前の日曜日、ウツ病と称して会社を休んでいる知人の家に行ってきました。スーパーでつまみを山ほど買い込んで、昼間からダラダラとウィスキー(Glenfiddich)を飲んでいました。
昔は胃潰瘍になるのがプログラマーの勲章だったけど、最近はウツ病になるのが勲章だよね。ホンモノのウツ病は朝4時に目が覚めるんだよね、などと話しつつ、ふと本棚の上のカレンダーに目が止まりました。普通のカレンダーだったのですが、珍しく月曜日始まりでした。大抵のカレンダーは一番左が日曜日、一番右が土曜日ですよね。
バッカスは月曜日始まりのカレンダーが好きで、日曜日始まりのカレンダーだと落ち着きません。何も考えずにカレンダーを見て、金曜日の夜に大宴会の予定を入れたつもりが実は木曜日だったので、次の日がえらく辛かった、などという失敗が多々あります。月曜日始まりのカレンダーを探すのに苦労をしていました。
最近はちょっと気の利いたソフトですと、週の始まりを変えられるようになっています。これで宴会の管理がずいぶん楽になりました。それでもショボいソフトですと、日曜固定のものがまだまだあります。携帯電話でもスケジュール管理機能に力を入れているものがありますが、メーカーによっては日曜固定で、その瞬間にバッカスは使う気が失せるのです。
これは国際化の問題である、と言ったら唐突でしょうか。私たちはほとんどアメリカと同じ慣習を使っているので、国際化といえば漢字の扱いに焦点が当たりがちですが、そもそも国際化の歴史は遠い昔、パソコンが漢字を扱えるようになるはるか以前、アメリカが初めてヨーロッパに進出した時から始まったのです。
日本やアメリカでは日曜日始まりのカレンダーが一般的ですが、ヨーロッパでは月曜日始まりが一般的です。アメリカのソフトウェア会社は、ドイツ語に翻訳をすれば、ドイツのマーケットでバンバン売れるぜ、ノープロブレム、などと思っていたのですが、木曜日に宴会をしてしまうドイツ人が続出したため、これではいかん、と真剣に考え始めたのが国際化の始まりでした。
もちろん翻訳をする以前にドイツ語の文字を扱えるようにならなくてはなりません。当時は一文字が7ビットだったのを8ビット化して、アクセント付き文字を含んだコード体系を整備したのです。ミュンヘンは「München」と書きますが、このテンテン付きの「u」がアクセント付き文字ですね。
国際化が必要だったのはカレンダーだけではありません。日付の記述方法も違いますし (e.g. 1/17/2007 → Jan 17 2007)、通貨記号も違う (e.g. $ → £)。数字の区切り記号が違う (e.g. 1,230.55 → 1.230,55) なんてのもあります。インドでは3桁づつではなく、2桁と4桁(だと思った、忘れた)に区切ったりもします。これは彼らの言語の関係で、例えば日本語では一、十、百、千、万、十万、百万、一千万、一億と区切るので、数字の区切りは4桁ずつにしてしまった、というようなものです。
国際会議などの同時通訳では、通常二人一組で仕事をします。一人が聞きながら大きなメモ用紙にどんどん単語を書いてゆく。もう一人はそれをチラチラ見ながら通訳していくのですが、数字が出てくると、必ず書きます。例えば「we have ten thousand users worldwide」とか言われると、「世界中」「10,000」と書くのです。しゃべる方は「10,000」を見て「一万」と言う。これは中国語も韓国語も同じで、彼らと話すときには、英語で話していても「ten mann」なんて言った方が間違いが少ない場合があります。アメリカ人ですら、日本に長く居すぎると「I had to pay ten man-en to that guy」なんて言い始めます。
このように国際化(Internationalization)をして、文字コード処理も入れて、そのうえに翻訳やローカルなコンテンツを入れて「xx語版」を作るのを Localization と言います。英語版ですら、ご存じのように米国式英語と英国式英語ではスペルが違う単語があるので (e.g. color=米国、colour=英国)、スペルチェック辞書の Localization をしなくてはなりません。
Internationalization は長いので、「i18n」と略されます。最初は何のことだか全く分からなかったバッカスですが、最初の「i」と最後の「n」の間に18文字、よって i18n と聞いて「なるほどね」と思った次第です。Localization は「l10n」。皮肉なことに、i18n や l10n は localization が必要です。実は localization は米国式で、英国式では localisation と綴るのです。日本語ですら「ローカライゼーション」と言ったり「ローカリゼーション」と言ったりします。
そんなこんなで国際化の話はまだまだ続きます。次回は BRICs、VISTA、BFIGS、ddnsf、BiDi なんてお話をさせていただきます。それではバッカスはこれから代官山に向かいます。お先に失礼します。
2.6.20-rc2 ~ 2.6.20-rc5 までの変更です。
-rc なので、大きい機能変更はないのですが、bugfix で大きいものがありました。
LWNで詳しく説明されているのでそちらを見ると面白いでしょう。
あとは、netdev (network driver) の修正、ALSA、V4L、ACPI、などの修正があります。
本日は「Red Black Tree」についての小ネタを。
以前も書きましたが、我々バックエンドチームでは毎週カーネルに関する勉強会をしています。ちょっと前にメモリマネジメントのネタを扱った際に、Red Black Tree(赤黒木)が出てきました。
年末の重い仕事が片付き、年も明けたところで心機一転、本題に突入です。
今回はNUMAの実機を用意しました。Dual Core Opteron を 2基搭載した(つまり論理プロセッサ数 4の)マシンです。
明けまして、おめでとうございます。
今回は、-rc の状態になり bugfix 以外にはあまり変更はありませんでしたので、前回で書いていないものをいくつか見てみたいと思います。
こんにちは、別な意味で病院の先生とも仲良くなってしまったtshojiです。
前回ソケットのシステムコールを載せました。今回は他のシステムコールを
載せる予定でしたが、以前勉強会でシステムコールの追加の仕方は
gitのログをみればすぐにわかります。という情報を頂いたので
今日はこちらを見てみることにしました。
こんにちは。
現在、Samba勉強中です。今日は、MiracleLinux V4.0 でのSWAT(Samba Web Access Tool)の簡単な使い方を紹介します。SWATは、Webブラウザ経由smb.confの設定を変更するツールです。
まずは、パッケージ名から!!現在(2006/12/15)の最新は、samba-swat-3.0.20b-1AXです。
前回からは、新しい merge window が開いたこともあり大量のコードが入りました。
fsレジスタを使って per cpu データにアクセスするコード (PDA) が追加されたり、そして paravirt の native hardware 用のハンドラや、mkdump の為に、relocatable なカーネルイメージのサポート、ちょっと前に紹介した KVM も Linus のツリーにマージされました。
その他には、workqueue の使用方法が変更されました。schedule_delayed_work() を使用するものとしないもので違う構造体を使うように変更がされ、遅延が必要なものは delayed_work 構造体、必要でないものは今までどうり work_struct 構造体を使用します。また、コールバックされるハンドラのインターフェースも変更されました。以前は "void *" だった、引数が "struct work_struct *" に変更されましたので注意が必要です。その他にも XXX_WORK_NAR が追加されたりしています。(linux-2.6/include/linux/workqueue.h)
みなさま、お疲れさまです。代官山のバッカスです。最近めっきり寒くなってきましたが、いかがお過ごしでしょうか。風邪などひかれていませんでしょうか。
さてバッカスはミラクルに就職したとき「自宅から会社のメールを見ることは決してするまい」と堅く心に誓いました。会社以外にするべきことは、短い人生、山ほどあるし、おうちに帰ってから酔っぱらった頭で会社のメールを処理すると、ろくなことにならないからです(検証済み)。
おうちの Macintosh から会社にアクセスする設定自体を、最初からしていませんでした。バッカスは意志が弱いので、環境があるとついやってしまうのが目に見えていたからです。快適でした。会社と関係ない Macintosh の生活は。
もう一つバッカスが避けたかったのが出張だったのですが、この前ついに、出張を命ぜられてしまいました。軽く抵抗してみたのですが、バッカスは試用期間中なのであまり逆らうわけにもゆかず、結局出かけてゆく羽目になってしまったのです。
そこで問題になるのがメール。もちろん何もしていないので「出張中はメールを見れません」というメールを流したのですが、それではイカンとのお言葉。これもまた紆余曲折があって、仕方がない、ついにリモートアクセスの設定をすることになってしまいました。この過程で一番効いたのは「あ、それ Mac だから...」という発言。「Mac だから」の後には「Windows みたいに環境が揃ってないし」とか「Linux の会社でそんなもの使って」という言葉が飲み込まれているのがミエミエです。くやしいじゃないですか。
外部から社内や学内のネットワークにアクセスする方法は色々あるようですが、unix 系のサーバだとssh(Secure Shell)を使うのが一般的なようです。そしてクライアントマシンが Windows の場合は懇切丁寧な設定方法のマニュアルが出回りますが、Macintosh 用のものはどこにもない。そこでここではバッカスの経験をシェアさせていただくことにしました。
ssh を使ってメールサーバに接続するには4つの段階があります。(1) 暗号キーの生成、(2) 暗号キーとアカウントの登録、(3) メールソフトの設定、(4) 接続。順を追って説明しましょう。
(1) キーの生成:サーバに接続するための個人キーを生成します。何種類かあるのですが、大体 RSA というタイプのものだと思います。例の Windows 用の手引き書があれば、サーバがどの種類のキーを使ってアクセスする設定になっているのか、必ず出ています。ここでは RSA キーを使います。
Finder からターミナルを起動します。Dock に登録されていないときは、アプリケーションフォルダのユーティリティフォルダから起動してください。おお素晴らしい。やはり Mac はunix マシンです。「Welcome to Darwin!」の文字を見てニッコリしてから、以下のコマンドを打ちます。
ssh-keygen -t rsa -v
色々言ってくるのに適当に答えていくと .ssh というディレクトリの中にキーが生成されます。id_rsa というのが自分で取っておく大切なキー。id_rsa.pub というのが人に渡すための公開キーです。これでキーの作成は終わり。
(2) キーの登録:次に公開キーをシステムに登録しなければなりません。これは会社や大学によって違うので、またまた例の Windows 用の手引き書を見てください。何も資料がなければ堂々と管理者に問い合わせましょう。教えてくれるはずです。バッカスの場合はミラクルの管理者に公開キーを送るとしばらくして「登録しました」と教えてくれました。同時に(もしまだなら)サーバ上のユーザ登録もしてくれます。
確認してみましょう。ネットワークにつながった状態で、ターミナルから例えば、
ssh baccus-d@gateway.hoge.co.jp
と入力してみます。「gateway.hoge.co.jp」は管理者が教えてくれる接続用のサーバ名です。最初の一回だけは「「gateway.hoge.co.jp」というホストを登録しますかぁ?」と聞いてくるので、yes としておくと次から聞いてきません。パスフレーズの入力を求められるので入力してやると、何もなければ無事に gateway.hoge.co.jp にログインできるはずです。
(3) メールソフトの設定:メールソフトの設定に入ります。OS X の Mail を使います。バージョンによって微妙に違いがあるので、ここではOS X バージョン 10.4.8 を使用。
(3-1) 「Mail」>「環境設定」を選択します。「アカウント」をクリックし、アカウントリストから ssh でつなぎたいアカウントを選択します。「アカウント情報」パネルの「受信用メールサーバ」には「pop.hoge.co.jp」というようなサーバ名が入っていますので、これを「localhost」という名前に書き換えます。
(3-2) 同じ「アカウント情報」パネルの下の方の「サーバ設定…」ボタンを押します。ドロップダウンの「送信用メールサーバ」に「smtp.hoge.co.jp」というようなサーバ名が入っていますので、これも「localhost」という名前に書き換えます。「サーバのポート」には「25」という数字が入っているので、これを「8025」に書き換えます。「OK」ボタンを押して確定します。あと一歩。
(3-3) 今度は「詳細」パネルを出すと、下の方に「ポート」とあって「110」という数字が入っています。これを「8110」に変更。環境設定を終了。「変更を保存しますか」に「はい」。これでメールの設定は完了です。
(4) 接続:いよいよ接続です。どきどき。コンソールから、
ssh baccus-d@gateway.hoge.co.jp -L 8110:pop.hoge.co.jp:110 -L 8025:smtp.hoge.co.jp:25
と入れてみてください。「gateway.hoge.co.jp」は接続用サーバ名、「pop.hoge.co.jp」は上の 3-1 で書き換えた受信用サーバ名、「smtp.hoge.co.jp」は同じく3-2 で書き換えた送信用サーバ名です。
パスフレーズを聞かれるので入力すると、手順(2)のときと同じようにログインできるはずです。この時点で localhost の 8110 は受信サーバの 110 につながっていますので、メールの受信をすれば無事に ssh 経由でサーバ上のメールが取り込めるはずです。
できましたでしょうか? めでたしめでたし。これで泥酔して家に帰っても、メールの処理ができるようになってしまいました。もちろんそれの引き起こす結果について、バッカスは責任を持てません。
注1:手順(2)で「WARNING: UNPROTECTED PRIVATE KEY FILE!」と言ってくるときがあります。もしかして id_rsa を Finder でコピーしませんでしたか? Finder はアクセス権を「全部あり」にしてしまうので、chmod 600 id_rsa をしておきましょう。
注2:手順(3)ではメールアカウントを書き換えていますが、別のアカウントを作っておいた方がいいかもしれません。自宅用と会社用にそれぞれ Mac が1台以上ずつある場合は、自宅では「メッセージ受信後にメッセージのコピーをサーバから取り除く」の選択をはずしておいた方がいいと思います。一日で消える設定だと、二日酔いで会社を休んだ次の日など、会社に着いたはいいけどメールが消えていた、なんてことになりかねません。
注3:サーバは必ずしもこのように分けられているとは限りません。関連するサーバ3台が全部同じという場合もあります。使用したアカウント名やサーバ名は架空のもので、実在のアカウント名やサーバ名とは一切関係ありません。
注3:手順(3-2)や手順(3-3)で指定する「8110」や「8025」は何でもいいのですが、バッカスの頭脳ではこの方が覚えやすいのでこうしています。「10000」と「20000」や「61485」と「29664」でも全く問題ないはずです。
注4:Entrouge でも同じようなことができると思いますが、バッカスは使っていないので分かりません。
それでは、また。
(次回は Mac で Vista! (の予定))
最近のカーネルに TCP MD5 Signature Option (RFC2385) のサポートが加わりました。(CONFIG_TCP_MD5SIG)
setsockopt(2) で鍵を設定しある程度(?)の攻撃から守る為の TCP のオプションのようで、BGP というプロトコルで使われているようです。
さらに、UDP-Lite (RFC3828) も加わりました (http://www.erg.abdn.ac.uk/users/gerrit/udp-lite/)。こちらは、冗長な UDP のペイロード長部分 (udphdr->len) を、UDP のチェックサムの摘要範囲の長さを入れておくように変えたもののようです。
VOIPなどの realtime 系で 1バイトぐらい動画データ壊れているぐらいじゃ、パケットを捨ててしまっては困る。それよりもこま落ちしない方がよっぽど重要だ、と言うときなどを目的に作られたようです(?)。(linux-2.6/Documentation/networking/udplite.txt)
バックエンドチーム は毎日たくさんのメールを受け取ります。
それらの中には、「サーバが落ちた」 とか 「今すぐ調査してくれ」 などのできれば見たくないメールだけでなく、ちょっと H なメールや買ってくれメールなどの スパムメール が結構な割合で混じっています。
これらの原因としましては、外部公開用のアドレスを悪の手先のロボットがせっせと収集し、悪の名簿に登録しているからです。
ミラクルリナックスは、feedback@ や info@ など、ミラクルユーザや一般の方々が弊社に直接アクセスできる窓口を公開しるため、収集されてしまうのは致し方ないのが現状です。
もちろん、ゲートサーバの口でフィルタしてますが、いたちごっこのようですね。
それでは、一番よい対策は何でしょう?
アドレスを外部公開しないことが一番でしょうが、そうもいきません。
以下のような対策は、悪の方々が多少頭がつかえれば、そんなものは簡単に変換して、アドレスにされてしまいます。
なので、私が知っている中で一番いいのは、以下のように画像を使うことです。
上記の方法を使うと、アドレスをコピペできなくなるので、ユーザビリティはもちろん下がってしまいます。
どう思いますか? ベターな案 プリーズ!
本日はバックエンドチームが行っていたパッチ解析勉強会のネタを書きます。
自分が担当してパッチは、
linux-2.6.9-usb-hid-disconnect.patch
になります。
パッチの中身は、下記のようになります。
1 --- linux-2.6.9-16.EL/drivers/usb/input/hid-core.c 2005-08-16 18:27:59.000000000 -0700
2 +++ linux-2.6.9-16.EL.z1/drivers/usb/input/hid-core.c 2005-11-15 09:21:18.000000000 -0800
3 @@ -918,14 +918,26 @@ static void hid_irq_in(struct urb *urb,
4 struct hid_device *hid = urb->context;
5 int status;
6
7 + if (urb->status == -EILSEQ) { /* unplug (on uhci) or other error */
8 + if (hid->error_count >= 20) {
9 + info("not resubmitting, input%d", hid->ifnum);
10 + return;
11 + }
12 + hid->error_count++;
13 + } else {
14 + hid->error_count = 0;
15 + }
16 +
17 switch (urb->status) {
18 case 0: /* success */
19 hid_input_report(HID_INPUT_REPORT, urb, regs);
20 break;
21 case -ECONNRESET: /* unlink */
22 case -ENOENT:
23 - case -ESHUTDOWN:
24 + case -EPERM:
25 + case -ESHUTDOWN: /* unplug */
26 return;
27 + case -EILSEQ:
28 case -ETIMEDOUT: /* NAK */
29 break;
30 default: /* error */
31 --- linux-2.6.9-16.EL/drivers/usb/input/hid.h 2004-10-18 14:53:06.000000000 -0700
32 +++ linux-2.6.9-16.EL.z1/drivers/usb/input/hid.h 2005-09-01 22:26:57.000000000 -0700
33 @@ -382,6 +382,8 @@ struct hid_device { /* device repo
34 char phys[64]; /* Device physical location */
35 char uniq[64]; /* Device unique identifier (serial #) */
36
37 + int error_count;
38 +
39 void *ff_private; /* Private data for the force-feedback driver * /
40 void (*ff_exit)(struct hid_device*); /* Called by hid_exit_ff(hid) */
41 int (*ff_event)(struct hid_device *hid, struct input_dev *input,
まず、スペックファイルのコメントを見てみました。
-fix endless loops in HID on disconnect (Pete Zaitcev) [167070]
コメントから、”切断時の無限ループの修正 ”だとわかります。
7 + if (urb->status == -EILSEQ) { /* unplug (on uhci) or other error */
8 + if (hid->error_count >= 20) {
9 + info("not resubmitting, input%d", hid->ifnum);
10 + return;
パッチで追加している処理をみると、20回に制限していることがわかります。
次に処理のルートをみてみしました。
hcd編
static struct usb_driver hid_driver = {
.probe = hid_probe,
--- 処理の流れ
hid_probe[drivers/usb/input/hid-core.c]
+-> usb_hid_configure[drivers/usb/input/hid-core.c]
+-> usb_fill_int_urb
+-> urb->completeにhid_irq_inを設定。
static const struct hc_driver uhci_driver = {
/* Generic hardware linkage */
.irq = uhci_irq,
--- 処理の流れ
uhci_irq[drivers/usb/host/uhci-hcd.c]
+-> uhci_transfer_result[drivers/usb/host/uhci-hcd.c]
| +-> uhci_result_control[drivers/usb/host/uhci-hcd.c]
| | +-> uhci_map_status[drivers/usb/host/uhci-hcd.c]
| : : -> -EILSEQ を設定。
| : :
+-> uhci_finish_completion[drivers/usb/host/uhci-hcd.c]
+-> uhci_finish_urb[drivers/usb/host/uhci-hcd.c]
+-> usb_hcd_giveback_urb[drivers/usb/host/uhci-hcd.c]
+-> urb->complete * 修正関数hid_irq_in を Call
uchi_map_status で -EILESEQを設定した場合にurb->completeで無限ループする可能性が
あることがわかりました。
まとめると
Linux カーネルへのパッチで NUMA に関係したソースコードを読む機会があり、ふと興味が沸きました。これから数回かけて、 Linux の NUMA 対応処理について調べてみたいと思います。
こんにちは、tshojiです。
バックエンドチームではカーネル勉強会を実施しています。
私にとっては毎回プレッシャーを感じていますが、 ここで解決できる問題がたくさんあるので大変有意義です。
第1回ではユーザーから見たLinuxカーネルということで、システムコールを調べてみました。といってもman2の内容ですが・・・
man2にはシステムコールの説明以外にもイントロや実装されていないシステムコールの 説明があります。
まず先にこれを読んでおくとman2を読み進め方がわかるのではないでしょうか。
| キーワード | 説明 |
| intro | システムコールの説明 |
| syscalls | システム・コールのリスト |
| unimplemented | 実装されていないシステムコール |
| afs_syscall | |
| break | |
| ftime | |
| getpmsg | |
| gtty | |
| lock | |
| mpx | |
| prof | |
| profil | |
| putpmsg | |
| security | |
| stty | |
| ulimit | |
| undocumented | ドキュメントがないシステム・コール |
| exit_group | |
| madvise1 | |
| rt_sigaction | |
| rt_sigpending | |
| rt_sigprocmask | |
| rt_sigqueueinfo | |
| rt_sigreturn | |
| rt_sigsuspend | |
| rt_sigtimedwait | |
| ugetrlimit | |
| obsolete | 廃止されたシステム・コール |
| oldfstat | |
| oldlstat | |
| oldstat | |
| oldolduname | |
| olduname |
次回はシステムコールの一覧を載せる予定です。
最近、-mm ツリーに面白そうなドライバが追加されました。KVM というドライバで Intel VT の機能を小さなモジュールで提供しています。
open() して、mmap() でメモリを割り当てられて、ioctl() で VM コンテキストを操作するようで、その他の必要なエミュレーションは全てユーザ空間で行われるようです (nice, kill などの通常の操作が出来る)。このドライバを書いた人は、既に qemu へのパッチも作成されていて、とても簡単に便利な仮想環境が作れそうです。
本日はミラクルリナックスのバックエンドチームが行っている勉強会のネタを書きます。
「バックエンドチーム = カーネルチーム」 と言う等式が 80% 程なりたつ我々は、仕事を何とかやりくりして、スキルアップすべく勉強会を開催しています。 時期によってネタは変わるのですが、ここしばらくは 「パッチの差分解析」 をやっていました。各メンバーに Redhat EL4 から適当なパッチを割り当て、担当者はそのパッチの意味や効果などを調査し、その調査結果を勉強会で発表する形式です。勉強会の席では、当然厳しいツッコミが入ります。担当者はウミガメのように涙を流しながら、がんばって発表しております(ウソ)。
で、ここから本題です。
-----------------------------------------------------------------------------------------
【 1. パッチの内容 】
今回は以下のパッチについての勉強会でした。
- linux-2.6.9-kallsyms-insmod.patch
48 --- linux-2.6.9/kernel/module.c.orig 2005-01-25 14:25:59.048764420 +0000
49 +++ linux-2.6.9/kernel/module.c 2005-01-25 14:28:24.746114719 +0000
50 @@ -1162,14 +1162,22 @@ static void mod_kobject_remove(struct mo
51 kobject_unregister(&mod->mkobj->kobj);
52 }
53
54 +/*
55 + * unlink the module with the whole machine is stopped with interrupts off
56 + * - this defends against kallsyms not taking locks
57 + */
58 +static inline int __unlink_module(void *_mod)
59 +{
60 + struct module *mod = _mod;
61 + list_del(&mod->list);
62 + return 0;
63 +}
64 +
65 /* Free a module, remove from lists, etc (must hold module mutex). */
66 static void free_module(struct module *mod)
67 {
68 /* Delete from various lists */
69 - spin_lock_irq(&modlist_lock);
70 - list_del(&mod->list);
71 - spin_unlock_irq(&modlist_lock);
72 -
73 + stop_machine_run(__unlink_module, mod, NR_CPUS);
74 remove_sect_attrs(mod);
75 mod_kobject_remove(mod);
76
77 @@ -1826,6 +1834,17 @@ static struct module *load_module(void _
78 goto free_hdr;
79 }
80
81 +/*
82 + * link the module with the whole machine is stopped with interrupts off
83 + * - this defends against kallsyms not taking locks
84 + */
85 +static inline int __link_module(void *_mod)
86 +{
87 + struct module *mod = _mod;
88 + list_add(&mod->list, &modules);
89 + return 0;
90 +}
91 +
92 /* This is where the real work happens */
93 asmlinkage long
94 sys_init_module(void __user *umod,
95 @@ -1860,9 +1879,7 @@ sys_init_module(void __user *umod,
96
97 /* Now sew it into the lists. They won't access us, since
98 strong_try_module_get() will fail. */
99 - spin_lock_irq(&modlist_lock);
100 - list_add(&mod->list, &modules);
101 - spin_unlock_irq(&modlist_lock);
102 + stop_machine_run(__link_module, mod, NR_CPUS);
103
104 /* Drop lock so they can recurse */
105 up(&module_mutex);
106
-----------------------------------------------------------------------------------------
【 2. 背景 】
kallsyms については知ってますか?
デバッガやトレーサーは以下の関数を利用して、モジュールのシンボル情報を取得できます。
(例)
- kallsyms_lookup
- kallsyms_lookup_name
- __print_symbol
例えば、kallsyms_lookup() の概要は以下のようになっています。
const char *kallsyms_lookup(unsigned long addr,
unsigned long *symbolsize,
unsigned long *offset,
char **modname, char *namebuf)
{
...
/* see if it's in a module */
msym = module_address_lookup(addr, symbolsize, offset, modname);
if (msym)
return strncpy(namebuf, msym, KSYM_NAME_LEN);return NULL;
}const char *module_address_lookup(unsigned long addr,
unsigned long *size,
unsigned long *offset,
char **modname)
{
struct module *mod;list_for_each_entry(mod, &modules, list) {
if (within(addr, mod->module_init, mod->init_size)
|| within(addr, mod->module_core, mod->core_size)) {
*modname = mod->name;
return get_ksymbol(mod, addr, size, offset);
}
}
return NULL;
}
要するに、modules からリストを辿っていき、調べたいモジュールに該当するシンボル情報を返すようになっています。
具体的には、list_for_each_entry(mod, &modules, list) で辿っていることが分かると思います。
module 構造体の概略は以下です。
struct module
{
enum module_state state;/* Member of list of modules */
struct list_head list;/* Unique handle for this module */
char name[MODULE_NAME_LEN];
...
/* If this is non-NULL, vfree after init() returns */
void *module_init;/* Here is the actual code + data, vfree'd on unload. */
void *module_core;/* Here are the sizes of the init and core sections */
unsigned long init_size, core_size;
...
}
ちなみに、実際のデータは以下のように入っています。先頭のデータは vfat のものですね。
これはダンプを crash コマンドで見たものですが、生きてきるシステムに対しても crash を利用することが可能ですので、気軽に確認してみてください。
crash> rd modules
c0329640: f93f8084 ..?.crash> struct module f93f8080
struct module {
state = MODULE_STATE_LIVE,
list = {
next = 0xf94e4004,
prev = 0xc0329640
},
name = "vfat\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\
000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\
000\000\000\000\000\000\000\000\000\000\000\000",
mkobj = 0xf7d52d80,
syms = 0x0,
num_syms = 0,
crcs = 0x0,
gpl_syms = 0x0,
num_gpl_syms = 0,
gpl_crcs = 0x0,
num_exentries = 0,
extable = 0x0,
init = 0xf93b4000,
module_init = 0x0,
module_core = 0xf93f5000,
init_size = 0,
core_size = 16896,
init_text_size = 0,
core_text_size = 6658,
...
symtab = 0xf93f7500,
num_symtab = 93,
strtab = 0xf93f7ad0 "",
sect_attrs = 0xf0a23000,
percpu = 0x0,
args = 0xeecd38c0 ""
}
-----------------------------------------------------------------------------------------
【 3. 問題点 】
で、ここからが本題の本題ですが、この元のコードの問題点はなんでしょう?
ちょっと見にくいのですが、【 1. パッチの内容 】 にあるパッチの - になっている行が元のコードです。
sys_init_module() や sys_delete_module() の中で、モジュールを modulelist から出し入れする際は、modlist_lock を取得して、競合が発生しないようにしていることが分かります。
しかし、【 2. 背景 】 で記載した kallsyms_lookup() や kallsyms_lookup_name() では、特にロックは取っていません。(これは、Oopsのパスで動くことがあるため、意図的にロックは取得していないということらしいです)
なので、一生懸命 sys_init_module() や sys_delete_module() が排他しても、kallsyms 側では勝手にリストを操作してしまいます。特に、kallsyms が list_for_each_entry(mod, &modules, list) でリストを辿る際、next がすでに NULLに なっていると、パニックが発生すると考えられます。
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member), \
prefetch(pos->member.next); \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member), \
prefetch(pos->member.next))
-----------------------------------------------------------------------------------------
【 4. 修正 】
この修正では、sys_init_module() や sys_delete_module() でロックを取得するのではなく、stop_machine_run() を利用し、他の CPU の処理を止めた(正確に言うと違うのですが、長くなったので割愛します)状態でモジュールの追加/削除を行うように変更しています。
stop_machine_run() では、ホットプラグ CPU のロックを取った後、各 CPU の割り込み、該当 CPU の割り込みを禁止します。
<pre>#ifdef CONFIG_SMP
/**
* stop_machine_run: freeze the machine on all CPUs and run this function
* @fn: the function to run
* @data: the data ptr for the @fn()
* @cpu: the cpu to run @fn() on (or any, if @cpu == NR_CPUS.
*
* Description: This causes a thread to be scheduled on every other cpu,
* each of which disables interrupts, and finally interrupts are disabled
* on the current CPU. The result is that noone is holding a spinlock
* or inside any other preempt-disabled region when @fn() runs.
*
* This can be thought of as a very heavy write lock, equivalent to
* grabbing every spinlock in the kernel. */
int stop_machine_run(int (*fn)(void *), void *data, unsigned int cpu);/**
* __stop_machine_run: freeze the machine on all CPUs and run this function
* @fn: the function to run
* @data: the data ptr for the @fn
* @cpu: the cpu to run @fn on (or any, if @cpu == NR_CPUS.
*
* Description: This is a special version of the above, which returns the
* thread which has run @fn(): kthread_stop will return the return value
* of @fn(). Used by hotplug cpu.
*/
struct task_struct *__stop_machine_run(int (*fn)(void *), void *data,
unsigned int cpu);#else
static inline int stop_machine_run(int (*fn)(void *), void *data,
unsigned int cpu) {
int ret; local_irq_disable();
ret = fn(data);
local_irq_enable();
return ret;
}
#endif /* CONFIG_SMP */
(あまりに長くなったので、__stop_machine_run() のコードはここに書きません)
-----------------------------------------------------------------------------------------
【 5. 結論 】
で、ここからが本題の本題の本題ですが、この修正で本当にいいのでしょうか?
__stop_machine_run() 及びその延長では、プリエンプションを禁止にしていません。
何が言いたいかというと、いくら kallsyms の実行を止めたからといって(kallsyms 的には一時的に時間の止まった状態)、list_for_each_entry(mod, &modules, list) でリストを辿っている最中にデバイスの追加/削除が行われたら、問題が発生するのは変わらないと思います。
実は勉強会もここで時間切れとなり、ここから先を調べるのは宿題となっております。
最新の 2.6.18 でもこの修正は残っているため、私の見落としているポイントがあり、本当はうまく修正されているのだと思います。(どこかでプリエンプションを禁止にしているか、それとも他の要因があるんだろうなー)
そのうち時間を作って調べたいと思いますので、結果はいつか書きたいと思っています。(書くかもしれなくもないという感じ)
では、また。
-----------------------------------------------------------------------------------------
最近のコメント