カーネルパニック

寒いですね〜.
おでんが恋しい季節になりました.

昨日はおでん屋に行こうと飲み屋街へ繰り出したものの,目当ての店を見つけられず・・・.でも飛び込みで入った居酒屋がなかなか良かったのが救いです.

KGDBを使ってみたかったので,Linuxマシンのカーネルを更新することにしました.
カーネル:2.6.18 -> 新カーネル:2.2.26

ところが,Volume group "VolGroup00" not foundと表示されてカーネルパニックが発生.LVM周りが原因っぽい.
いろいろ調べたところ,LVMのドライバを有効にする必要があるらしいことが判明.

menuconfigを起動

#make menuconfig

LVMのドライバを有効にします.

Device Drivers  --->
    [*] Multiple devices driver support (RAID and LVM)  --->
        <*>   Device mapper support

再度コンパイル&インストール.
これで正常に起動するようになった.

Apacheモジュールで排他制御を行う

前回,Apacheモジュールで共有メモリを使うには - 房総爆釣日記で作ったモジュールに排他制御の機能を追加します.
まず,次の二つのヘッダファイルを追加します.

#include "apr_global_mutex.h"
#include "unixd.h"

ServerConfig構造体に,mutexが使うファイルの名前と,mutexのアドレスを格納するメンバを追加します.

typedef struct ServerConfig{
        char *mutex_path;
        apr_global_mutex_t *mutex;

        char *shm_path;
        apr_shm_t *shm_data;

        int *access_count;
}sconfig;

post_configステージでcreate mutexします.

                //Create global mutex
                status = apr_global_mutex_create(&(config->mutex), config->mutex_path, APR_LOCK_DEFAULT, p);
                if(status != APR_SUCCESS){
                        DEBUGLOG("create gloval mutex faild");
                        return HTTP_INTERNAL_SERVER_ERROR;
                }
#ifdef AP_NEED_SET_MUTEX_PERMS
                status = unixd_set_global_mutex_perms(config->mutex);
                if(status != APR_SUCCESS){
                        DEBUGLOG("Parent could not set permissions on globalmutex");
                        return HTTP_INTERNAL_SERVER_ERROR;
                }
#endif

ここのifdefでは,mutexのパーミッションの設定が必要かどうかを,AP_NEED_SET_MUTEX_PERMSで判定している模様.
unix系のOSではこの記述が必要らしい.
私の環境(Linux)ではこの記述がないとmutexの作成に失敗しました.

child_initステージでmutexにアタッチ

                       if(apr_global_mutex_child_init(&config->mutex, config->mutex_path, p))
                                DEBUGLOG("global mutex attached!");

ここまででmutexを使う準備が完了.実際に排他制御するときはクリティカルセクションの初めで

       status = apr_global_mutex_lock(config->mutex);

とします.戻り値をみてロックが成功したかどうか判定してやる必要があります.
ロックの解除はこれ.

       status = apr_global_mutex_lock(config->mutex);
続きを読む

ApacheモジュールからサーバのプロセスIDを取得する方法

ApacheモジュールからサーバのプロセスIDを取得する方法.
とっても簡単.getpid()を使う.
まず,つぎの2つのヘッダファイルをインクルードしておく.

#include <sys/types.h>
#include <unistd.h>

pidを取得したいところで

pid_t pid = getpid();

とすればよろし.

Apacheモジュールで共有メモリを使うには

訳あって,Apacheモジュールを書くことに.
Apacheモジュール開発の導入に関してはDSAS開発者の部屋:apache module 開発事始めが大変参考になりました.

ここではAPR(Apache Portable Runtime)の機能を使って,共有メモリを使う方法を書きます.
このモジュールはApache複数プロセス)が,アクセスを受けた回数をエラーログに出力するという単純なもの.

なお簡単のためにディレクティブは使用しません.(キリッ
排他制御もやってません.(キリッ 
でも排他制御はそのうち触れたい.
では早速ソースを...

#include "httpd.h"
#include "http_config.h"
#include "http_protocol.h"
#include "ap_config.h"

#include "http_log.h"
#include "apr_time.h"
#include "apr_shm.h"

#define USER_DATA_KEY "shm_counter"
#define DEBUGLOG(...) ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, NULL, __VA_ARGS__)
module AP_MODULE_DECLARE_DATA shm_counter_module;

typedef struct ServerConfig{
	char *shm_path;
	apr_shm_t *shm_data;
	int *access_count;
}sconfig;

static void *create_server_config(apr_pool_t *p, server_rec *s){
	sconfig *config;

	config = (sconfig *)(apr_palloc(p, sizeof(sconfig)));

	config->shm_path = "/tmp/shm_counter";
	config->shm_data = NULL;

	return config;
}

static int post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s){
	sconfig *config;
	void *user_data;
	apr_status_t status;

	apr_pool_userdata_get(&user_data, USER_DATA_KEY, s->process->pool);

	if(user_data == NULL){
		apr_pool_userdata_set((const void *)1, USER_DATA_KEY, apr_pool_cleanup_null, s->process->pool);
		return OK;
	}

	do{
		config = (sconfig *)(ap_get_module_config(s->module_config, &shm_counter_module)); 
		DEBUGLOG("%s", config->shm_path);
		//raise(SIGTRAP);
                status = apr_shm_remove(config->shm_path, p);
		if (status == APR_SUCCESS) {
	        	DEBUGLOG("removed the existing shared memory segment name");
	        }

		status = apr_shm_create(&(config->shm_data), sizeof(int), config->shm_path, p);
		
		if(status != APR_SUCCESS){
			return HTTP_INTERNAL_SERVER_ERROR;
		}
		config->access_count = (int *)(apr_shm_baseaddr_get(config->shm_data));

		*(config->access_count) = 0;
	}while((s=s->next) != NULL);

	return OK;
}
	
static void init_child(apr_pool_t *p, server_rec *s)
{
	sconfig *config;
	do{
		config = (sconfig *)(ap_get_module_config(s->module_config, &shm_counter_module));
		//raise(SIGTRAP);

		if(!config->shm_data){
			if(apr_shm_attach(&(config->shm_data), config->shm_path, p) != APR_SUCCESS){
				ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0 , 0, "shm attached!");
				return;
			}
		}
	}while((s = s->next) != NULL);

}
static int shm_counter_handler(request_rec *r)
{
	sconfig *config;

	config = (sconfig *)(ap_get_module_config(r->server->module_config, &shm_counter_module));

	(*config->access_count)++;

	DEBUGLOG("ACCESS_COUNT=%d", *config->access_count);
	return OK;
}

static void shm_counter_register_hooks(apr_pool_t *p)
{
   	ap_hook_access_checker(shm_counter_handler, NULL, NULL, APR_HOOK_MIDDLE); 
	ap_hook_post_config(post_config, NULL, NULL, APR_HOOK_MIDDLE);
	ap_hook_child_init(init_child, NULL, NULL, APR_HOOK_MIDDLE);
}

/* Dispatch list for API hooks */
module AP_MODULE_DECLARE_DATA shm_counter_module = {
	STANDARD20_MODULE_STUFF, 
	NULL,                  /* create per-dir    config structures */
	NULL,                  /* merge  per-dir    config structures */
	create_server_config,  /* create per-server config structures */
	NULL,                  /* merge  per-server config structures */
	NULL,                  /* table of config file commands       */
	shm_counter_register_hooks  /* register hooks                      */
};

Apacheがこのモジュールを読み込むと,module構造体のcreate per-server config structuresに登録されているcreate_server_configを実行し,サーバのこのモジュールに関する設定を行います.
sconfig構造体のshm_pathは,共有メモリで使用するファイルを指定します.
ファイルは,実際に読み書き可能なディレクトリに置く必要があります.私はここでハマりました.


apacheはpost_configステージに達すると,post_configを呼び出します.
post_configでは,apr_shm_createで共有メモリを作成し,apr_shm_baseaddr_getで実際に使用するデータ領域のアドレスを取得します.
apr_shm_createの前のapr_shm_removeは,サーバが異常終了するなど,共有メモリで使用していたファイルが削除されずに残った場合,これを削除するためのものです.


child_initステージでは,自分が共有メモリにアタッチしているか否かを判定し,アタッチしていない場合にapr_shm_attachを使ってアタッチします.


これで,起動時の処理はおしまいです.
ブラウザからアクセスされるたびにshm_counter_handlerが呼ばれます.
errorログにアクセスカウントが記録されているはずです.

参考:
DSAS開発者の部屋:apache module 開発事始め
http://acapulco.dyndns.org/mod_uploader/module_dev.htm

Linuxマシン再インストールメモ

研究室で使っている開発用Linuxマシンの再インストールを行った.
そもそも操作ミスで/sbin以下を全部キレイにしちゃったのが原因で・・・.

ディストリビューションは以前から使っていたCentOSを採用.
インストールオプションはデフォルトのまま.

yumで追加インストールしたパッケージは次の通り.足りないものがあれば順次追加する.
gcc
kernel-devel
kernel-headers
gdb

Apacheモジュールの開発のためにデフォルトで入っていたApacheをremove.
ソースをコンパイルしてインストールした.

#./configure --with-included-apr
#vi Makefile

で,

EXTRA_CFLAG=g

としておく.これでデバッグシンボルを含んだバイナリが生成される.

#make
#make install

これで作業完了./usr/local/apache2以下にインストールされる.

スーパーpre記法の練習

プログラムリストを張り付ける際など,改行やインデントをそのまま表示したいことがある.
その場合,はてなスーパーpre記法っていうのを使えばいいらしい.
入力したプログラムコードを色付けするスーパーpre記法 シンタックス・ハイライトの実装について - はてなダイアリー日記

#include "httpd.h"
#include "http_config.h"
#include "http_protocol.h"
#include "ap_config.h"

#include "http_log.h"
#include "apr_time.h"
#include "apr_shm.h"

#define USER_DATA_KEY "snic_attack_detector"
module AP_MODULE_DECLARE_DATA dosadm_module;

typedef struct ServerConfig{
        char *shm_path;
        apr_shm_t *shm_data;
        int *access_count;
}sconfig;

static void *create_server_config(apr_pool_t *p, server_rec *s){
        sconfig *config;

        config = (sconfig *)(apr_palloc(p, sizeof(sconfig)));

        config->shm_path = "/tmp/ccc";
        config->shm_data = NULL;

        return config;
}

すげー,できたできたー!