Pylone

Pylone Blog

jffs2イメージをloopback mount

Posted by Seiichi SATO

block2mtdドライバを使えば、jffs2イメージファイルをloopbackでmountできます。

erasesize 128K (131072) のrootfs.jffs2を/mntにmountする場合

mount:

# modprobe jffs2
# modprobe mtdblock
# losetup /dev/loop0 rootfs.jffs2
# modprobe block2mtd block2mtd=/dev/loop0,131072
# mount -t jffs2 -o ro /dev/mtdblock0 /mnt

umount:

# umount /mnt
# rmmod block2mtd
# losetup -d /dev/loop0

seq_fileの使い方

Posted by MINAMI Hirokazu

Linuxカーネルが持つ、疑似ファイルの実装を補助する機構を紹介します。

カーネルからユーザ空間へデータを渡す手段としては、/proc や /sys 以下に作成した疑似ファイルを使うことが多いでしょう。

渡したい値が単純な型の場合はカーネル組込みのヘルパ関数を使えば十分(sysfs 経由でモジュールパラメータにアクセスsysfs 経由でモジュールパラメータにアクセス (2))ですが、 より複雑なデータを渡すならば:

  • 疑似ファイルの内容となるテキスト量が大きい場合、カーネル空間に全体を保持たくない。
  • データ構造を操作に時間がかかる場合、ユーザ空間から要求された部分だけを処理することが望ましい。
  • 同時に複数の読み手が存在したり、読み出し途中でデータが変更される場合の排他が必要。

などの点を考慮するべきです。

本記事では、シーケンシャルな疑似ファイルを実装するために用意されている補助関数群について解説します。カーネル内でも広く使われている機構なので、知っておくとコードを読む際にも役立つでしょう。

seq_file

VFSの層ではファイル中の位置はバイト単位で扱われます。固定長のバッファで扱える程度のデータ量ならよいのですが、疑似ファイル内容を一括生成・保持できない場合、自力で出力済のバイト数管理やバイト単位でのシークを実装するのは手間がかかります。

fs/seq_file.cには出力したいデータが

  • 通し番号が付けられる(配列や木などの)要素の集合として表現できる
  • 要素の番号がわかれば、その要素の文字列表現が得られる

という条件を満たすとき、各要素へのアクセスをイテレータ操作として抽象化する仕組みが用意されています。

これを使うと、所定のアクセサを作成するだけで、VFSに登録する struct file_operations のメンバのほとんどをカーネルから提供される汎用関数でまかなうことができます。

使用例

サンプルとして、全ttyについてdebugfs上の疑似ファイル経由として termios状態を一覧するカーネルモジュールのソースtermios_dumper.cを用意しました。

個別のttyの状態取得ならtcgetattr()でも十分なのですが、システム上で現在activeな全てのttyをリストするために、カーネル内部のデータ構造を直接読んでいます。

疑似ファイルの登録

seq_fileを使用する場合でも、ファイルシステムへの疑似ファイルの登録は通常のまま

  1. struct file_operationsを作成
  2. ファイルシステム毎の登録関数の呼び出し

という手順で行います。

ただし、VFSに渡すstruct file_operationsのうち、読みこみ可能な疑似ファイルを実装するために必要な

  • open
  • read
  • llseek
  • release

のうちread, llseek, releaseとしては、seq_fileで実装されているseq_read, seq_lseek, seq_releaseをそのまま使用できます。

.openに登録する関数では、

  • open()されたファイルに対して、seq_open()を呼んでハンドラを登録。
  • 必要ならリソースの確保/ロック

を行ないます。

サンプルでは登録先のファイルシステムをdebugfsとしたので、以下のようにしています。

static const struct file_operations fops = {
.open = termios_dumper_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
...
static int __init termios_dumper_init(void)
{
...
if(IS_ERR(fs_root = debugfs_create_dir(KBUILD_BASENAME, NULL)))
return PTR_ERR(fs_root);
if(IS_ERR(fs_file = debugfs_create_file("state", 0444, fs_root, NULL,
&fops)))
return PTR_ERR(fs_file);

この例では、特にリソースの初期化が必要ないため、.openに登録したtest_seqfile_openの実装はseq_open()の呼び出しだけです。

static int test_seqfile_open(struct inode *inode, struct file *file)
{
return seq_open(file, &seqfile_ops);
}

seq_operations

読み出し用のイテレータに必要な操作:

  • 初期化
  • 終了処理
  • 「次」の要素に移動
  • 値(文字列表現)の取得

は、

struct seq_operations {
void * (*start) (struct seq_file *m, loff_t *pos);
void (*stop) (struct seq_file *m, void *v);
void * (*next) (struct seq_file *m, void *v, loff_t *pos);
int (*show) (struct seq_file *m, void *v);
};

の各メンバとして登録されます。

start

seq_file用のファイルがopen()された時に呼ばれます。

  • 使用するリソースの確保
  • イテレータの初期化

を行ない、成功した場合には初期化済みのイテレータ、失敗した場合はNULLを返すことになるでしょう。

引数*posが0より大きい場合には、その位置を指すようにしたイテレータが返却されるべきです。

※ イテレータの更新処理は、(pos)ではなく、(*pos)を使います。

イテレータを進める処理は、next()からの処理でも必要となるため、共通化してもよいでしょう。サンプルでは update_iterator()としています。

next

seq_fileが、現在のイテレータからのデータを消費し終えた時、現在のイテレータと次に指すべき位置を引数として呼ばれます。

読み手のread()に対応していると考えてよいでしょう。ただし、カーネルによる先読み処理の対象となるため、read()の度にかならず呼ばれるわけではありあせん。また、読み手が小量のデータしが要求していなくても、さらに先まで要求されることがあります。

指定位置を指すイテレータを用意して、それへのポインタを返します。この場合返却したポインタは後述するshow()への引数として使われます。

処理に失敗した場合はNULLを返却します。このとき、続いてstop()が呼ばれますが、stop()の引数にはNULLしか渡らないため、リソースの開放にイテレータが必要なら、next()内で済ませておく必要があります。

stop

読み手に十分なテキストが渡ったか、next()からデータがもうないことを通知した(NULLを返した)後に呼びだされます。

リソースの開放を行なうべきですが、引数として渡されるポインタはNULLの場合があることに注意が必要です。

show

引数として渡されたイテレータから、読み手に渡す(疑似ファイルの内容となる)文字列を構築します。

構築にはseq_printf(), seq_puts()などのヘルパ関数を使用します。これらのヘルパは繰替えし呼ぶこともでき(追記されます)、最終的な長さは自動的に管理されるので、成功時には0を返せば適切に処理されます。

ただし、一度に構築できる文字列の全長はPAGE_SIZE程度なので、長くなりすぎる場合はイテレータの構造を変える必要があるでしょう。

サンプルコードでは、現在のイテレータが指しているtermiosの情報を、seq_printf()経由でgrepしやすい書式に変換しています。

サンプルtermios_dumper.cについての補足

サンプルとして使用したコードtermios_dumper.cでは、カーネルから公開されていはいttyドライバのリストの先頭要素のアドレスを知るために、struct tty_driverのmagic要素を用いて検索していますが、これは低い確率ですが(メモリ中の値が偶然TTY_MAGICと一致したり、get_current_tty()が呼べない場合に)失敗する可能性のある処理です。確実を期すなら、カーネルの公開シンボルにtty coreのtty_driversを追加するか、専用のアクセサを追加するべきでしょう。

また、ttyサブシステム内の構造体を辿る処理はttyのmutexを取得した上で行うべきなのですが、

  • tty_mutexを占有すると副作用が大きい(ロック中に新規にttyを開こうとした他のプロセス全てが停止するため)
  • 改造して失敗したときにシステムをロックしてしまう
  • 今回のサンプルでは読み出ししかおこなわないため、整合性が崩れても大きな問題にならない

ため、デモ目的では不要と判断してコメントアウトしてあります。このため、疑似ファイルからの読出し途中でttyが増減すると、表示の一貫性が崩れることがあるでしょう。同様の理由で、kobjectの参照数カウントについても省略しています。

sysfs 経由でモジュールパラメータにアクセス (2)

Posted by Seiichi SATO

以前の記事で sysfs からモジュールパラメータにアクセスする簡単な方法を紹介しましたが、今回はパラメータの型を独自に定義する例として Base36 のパラメータを持つ簡単なモジュールを紹介します。

コード

base36param.c:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
static int stored_value = 0;
static int param_set_base36(const char *val, struct kernel_param *kp)
{
if (('0' <= val[0]) && (val[0] <= '9')) {
stored_value = val[0] -'0';
return 0;
}
if (('a' <= val[0]) && (val[0] <= 'z')) {
stored_value = val[0] -'a' +10;
return 0;
}
if (('A' <= val[0]) && (val[0] <= 'Z')) {
stored_value = val[0] -'A' +10;
return 0;
}
return -EINVAL;
}
static int param_get_base36(char *buffer, struct kernel_param *kp)
{
if (stored_value < 0 || 36 < stored_value)
return -EINVAL;
if (stored_value < 10)
buffer[0] = '0' + stored_value;
else
buffer[0] = 'A' + stored_value - 10;
buffer[1] = '\0';
return 2;
}
/* dummy checker */
#define param_check_base36(name, p) __param_check(name, p, void);
static int __init base36param_init(void)
{
printk(KERN_INFO "%s called\n", __func__);
return 0; /* succeeded */
}
static void __exit base36param_cleanup(void)
{
printk(KERN_INFO "%s called\n", __func__);
return;
}
module_init(base36param_init);
module_exit(base36param_cleanup);
module_param(stored_value, base36, 0644);
MODULE_PARM_DESC(stored_value, "can write [0-9A-Za-z], read as [0-9A-Z].");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("MINAMI Hirokazu");
MODULE_DESCRIPTION("sample module which has a custom typed parameter");

Makefile:

KERNEL_SRC = /lib/modules/$(shell uname -r)/build
#CROSS_COMPILE =
#ARCH =
BUILD_DIR := $(shell pwd)
VERBOSE = 0

obj-m := base36param.o

all:
	make -C $(KERNEL_SRC) SUBDIRS=$(BUILD_DIR) KBUILD_VERBOSE=$(VERBOSE) modules

clean:
	rm -rf *.o *.ko *.mod.c .*.cmd .tmp_versions *~ Module.symvers

ビルド

環境に応じて Makefile の KERNEL_SRC, CROSS_COMPILE, ARCH を修正し、make を実行します。

使い方

値 (Base36) をパラメータに書き込む:

# echo 'h' > /sys/module/base36param/parameters/stored_value

パラメータを読み込む:

# cat /sys/module/base36param/parameters/stored_value
H

解説

モジュールパラメータに独自の型を持たせるためには、module_param を使います。

module_param(stored_value, base36, 0644);

module_param は以下のようなマクロです。

/* Helper functions: type is byte, short, ushort, int, uint, long,
   ulong, charp, bool or invbool, or XXX if you define param_get_XXX,
   param_set_XXX and param_check_XXX. */
#define module_param_named(name, value, type, perm)			   \
	param_check_##type(name, &(value));				   \
	module_param_call(name, param_set_##type, param_get_##type, &value, perm); \
	__MODULE_PARM_TYPE(name, #type)

#define module_param(name, type, perm)				\
	module_param_named(name, name, type, perm)

param_set_##type と param_get_##type が肝です。sysfs 経由でパラメータが読み書きされると、ここで登録されるparam_set_##type と param_get_##type が呼ばれます。(module_param_call の説明は省きます)

base36param.c の場合、プリプロセッサによってマクロ展開されたparam_set_base36 と param_get_base36 が登録されることになります。

マクロのコメントにある通り、 独自の型ではなく int などの場合はあらかじめ用意されているヘルパー関数群が使われるので自前で用意する必要はありません。

先日公開した 仮想バッテリドライバ はこれの応用です。 ファイルとして読み書きできるので ユーザ空間のプログラムとヘッダを共有する必要がない点は ioctl(2) より使い勝手がよいかもしれません。

関連記事

usbmon

Posted by MINAMI Hirokazu

Linux kernel 組込みの USB サブシステムをモニタする仕組み(usbmon)について紹介します。debugfs の活用例としても参考になるのではないでしょうか。

前提

Linux kernel 2.6.21以降を

  • CONFIG_USBMON
  • CONFIG_DEBUGFS

を有効にしてコンパイルした環境が必要です。

準備

  1. debugfsがまだマウントされていなければマウントします。 一般的に /sys/kernel/debug/ にマウントされるため、
    # mount -t debugfs none /sys/kernel/debug
    すればよいでしょう。
  2. usbmon をモジュールとして作成していた場合、カーネルに組み込みます。
    # modprobe usbmon

以上の手順を実行すると、debugfs の下(/sys/kernel/debug/usbmon/) に、「番号 + "s"/"t"/"u"」 という仮想ファイル群が生成されているはずです。

$ ls /sys/kernel/debug/usbmon/
0s  0u  1t  2s  2u  3t  4s  4u  5t  6s  6u
0t  1s  1u  2t  3s  3u  4t  5s  5u  6t

実際に何個のファイルが見えるかは、システム構成によります。

キャプチャ

「USBバス番号 + 'u'」という名前のファイルに、USBの通信内容が配送されます。

とりあえずバス番号に 0 を指定して("0u"を使って)、全通信を監視してみるとよいでしょう。

# cat  /sys/kernel/debug/usbmon/0u
dfaac8c0 2557329542 S Bo:5:004:2 -115 31 = 55534243 214b0100 00000000 00000600 00000000 00000000 00000000 000000
dfaac8c0 2557329639 C Bo:5:004:2 0 31 >
dfaac8c0 2557329649 S Bi:5:004:2 -115 13 <
dfaac8c0 2557331148 C Bi:5:004:2 0 13 = 55534253 214b0100 00000000 01
dfaac8c0 2557331171 S Bo:5:004:2 -115 31 = 55534243 224b0100 12000000 80000603 00000012 00000000 00000000 000000
dfaac8c0 2557331388 C Bo:5:004:2 0 31 >

行の内容は以下のようになっています。

  • URB Tag
  • timestamp
  • Event Type (S - submission, C - callback, E - error)
  • 通信種類([CZIB][io]): バス番号 : Device address : Endpoint number
  • URB Status word
  • データ長さ
  • データ内容

特定のデバイスだけを監視したい場合、lsusb の結果を参考にするとよいでしょう。たとえば

$ lsusb |grep PL2303
Bus 005 Device 005: ID 067b:2303 Prolific Technology, Inc. PL2303 Serial Port

のようになっていた場合、 PL2303(USB-シリアルコンバータ)が5番に接続されているので、5uを使えばよいことがわかります。

その他の情報

疑似ファイルには他に 't'/'s'でおわるものがあります。

't'でおわるもの

'*t' は互換性のために残されている古い書式の疑似ファイルなので、通常使用する必要はないでしょう。

's'でおわるもの

'*s' からは usbmon 自体の動作状況を読むことができます。たとえば

# cat /sys/kernel/debug/usbmon/5s
nreaders 1 events 350 text_lost 0

なら、

  • 現在 1つのプロセスが バス#5 を監視して中
  • いままでに 350 個のURBが読み出された
  • 読まれる前にバッファから溢れてしまった URB はない

ことがわかります。

's' で終わるファイル群の処理では排他制御が考慮されないため、このインターフェース経由に高負荷をかける場合は何をしているのかよく理解した上で行なってください。

busybox-staticによるinitramfs

Posted by Seiichi SATO

カスタムボードへのLinuxカーネル移植の初期段階でとりあえずのrootfsが必要になる場合は多いと思います。とりあえずのものにそれほど手間はかけたくないですが、カーネルのデバッグや動作確認のために機能はそれなりに欲しいところです。

方法は色々あると思いますが、パイロンではDebianの busybox-staticパッケージinitramfsを使うことが多いです。 手順は以下の通りです。

(例としてrootfsのディレクトリを/PATH/TO/ROOTFS/とします)

  1. busybox-staticパッケージをdpkg -xでばらしてbin/busyboxを/PATH/TO/ROOTFS/bin/busyboxにコピー
  2. /PATH/TO/ROOTFS/bin/busyboxへのシンボリックリンクPATH/TO/ROOTFS/initを追加
  3. mkdir /PATH/TO/ROOTFS/{dev,etc,proc}
  4. mknod /PATH/TO/ROOTFS/dev/console c 5 1

busyboxのinitは/etc/init.d/rcSを読み込むので起動直後の処理はrcSに加えます。最低でも/procのマウントさえしておけばよいでしょう。

/PATH/TO/ROOTFS/etc/init.d/rcS:

#!/bin/sh
mount -t proc proc proc

カーネルにinitramfsとして組み込むにはCONFIG_BLK_DEV_INITRDとCONFIG_INITRAMFS_SOURCEを指定します。

CONFIG_BLK_DEV_INITRD=y
CONFIG_INITRAMFS_SOURCE=/PATH/TO/ROOTFS/

debootstrapの前半部分をホストで、後半をターゲットで行う手順

Posted by Seiichi SATO

何もインストールされていないターゲット向けにDebian基本システムを作る手順です。Debianの作法的に正しいかどうかはわかりません。

ホスト側で前半部分を実行

NFS-Rootのホスト側ディレクトリを/nfsroot/etch-ARCH として説明します。

ARCHはアーキテクチャ(arm, mipsel, powerpcなど)に置き換えてください。

debootstrapを--foreignオプションで実行します。

# debootstrap --foreign --arch ARCH etch /nfsroot/etch-ARCH http://ftp.debian.org/debian/

NFS-Root用の/etc/fstabを用意します。

# echo "proc /proc proc defaults 0 0" > /nfsroot/etch-ARCH/etc/fstab
# echo "ホストのIPアドレス:/nfsroot/etch-ARCH / nfs defaults 0 1" >> /nfsroot/etch-ARCH/etc/fstab

/dev/consoleを作ります。

# mknod /nfsroot/etch-ARCH/dev/console c 5 1

NFS-Rootでターゲットを起動

NFSサーバの設定については触れません。

カーネルパラメータでホストの/nfsroot/etch-ARCHをNFS-Rootとして指定してカーネルを起動します。

カーネルパラメータの例:

console=ttyS0,115200n8 root=/dev/nfs nfsroot=ホストのIPアドレス:/nfsroot/etch-ARCH/ ip=ホストのIPアドレス:::サブネットマスク::eth0: init=/bin/sh

ターゲットで後半部分を実行

debootstrapを実行するための準備をします。
# mount -n -o remount,rw /
# mount -n /proc
# export PATH=/bin:/sbin:/usr/bin:/usr/sbin
# date -s "2008-2-27 18:33"
debootstrapを--second-stageオプションで実行します。
# /debootstrap/debootstrap --second-stage --no-resolve-deps

ターゲット向けの設定について

上記手順で作成したDebian基本システムをターゲットのNANDやCFなどにインストールして使う場合、事前にターゲットの環境に合わせて設定が必要になります。

よくある設定としては

  • /etc/inittab
  • /etc/fstab
  • /etc/securetty
  • /etc/resolv.conf
  • /etc/network/interfaces

といったところでしょうか。

シリアルコンソールであればttySnも作っておくといいかもしれません。

# cd /nfsroot/etch-ARCH/dev
# ./MAKEDEV ttyS

リンク

dpkg-crossの--exclude オプション

Posted by Seiichi SATO

dpkg-crossの基本的な使い方を知っている方向けの記事です。

dpkg-crossの--excludeオプションはクロスへ変換する際にDependsから特定のパッケージを取り除くオプションです。 最近追加 されたらしいのですが、使ってみたら便利だったので紹介します。

こんな感じです。

普通にクロスパッケージ化すると

$ dpkg -f lib64gcc1_4.1.1-21_powerpc.deb | grep Depends
Depends: gcc-4.1-base (= 4.1.1-21), libc6-ppc64 (>= 2.3.6-7)
$ dpkg-cross -a powerpc -b lib64gcc1_4.1.1-21_powerpc.deb
Building lib64gcc1-powerpc-cross_4.1.1-21_all.deb
$ dpkg -f lib64gcc1-powerpc-cross_4.1.1-21_all.deb | grep Depends
Depends: gcc-4.1-base (= 4.1.1-21), libc6-ppc64-powerpc-cross (>= 2.3.6-7), libc6-ppc64-powerpc-dcv1

となります。

--excludeを使ってgcc-4.1-baseへの依存を削ると

$ dpkg-cross -a powerpc -b --exclude gcc-4.1-base lib64gcc1_4.1.1-21_powerpc.deb
Building lib64gcc1-powerpc-cross_4.1.1-21_all.deb
$ dpkg -f lib64gcc1-powerpc-cross_4.1.1-21_all.deb | grep Depends
Depends: libc6-ppc64-powerpc-cross (>= 2.3.6-7), libc6-ppc64-powerpc-dcv1

となります。

ディスクイメージのホスト側での操作方法

Posted by MINAMI Hirokazu

QEMUなどのシステムエミュレータでは、エミュレートされるシステムに対して仮想的なデバイスを見せることができます。 ハードディスクなどの記憶装置を模擬する場合、ディスクイメージをファイルとして作成して使うことが多いでしょう。

今回は、このディスクイメージを仮想環境の外側で作成/操作する手段について紹介します。

作業環境としてはLinuxを想定しています。

イメージの作成

希望の構成のディスクイメージを、ホスト環境で作成する手順を説明します。

ファイル作成

まず希望のデバイスサイズのファイルを用意します。

サイズさえ十分ならどのようにしても構いませんが、ddで作ることをおすすめします。例えば 512 MBytes のものを作りたいなら

$ dd if=/dev/zero of=FILENAME bs=1 count=1 seek=536870911

とするとよいでしょう。(seek= の値は、512 MBytes = 524288 KBytes = 536870912 Byte なので、536870912-1 を指定しています)

素朴に /dev/zero からコピーして

$ dd if=/dev/zero of=FILENAME bs=1M count=512

としてもよいのですが、近代的な(ファイルにholeが作れる)ファイルシステムで作業しているならseek させた方が終了が早く、実ディスク消費も抑えられます。

パーティション作成

エミュレーションされる環境を実際の環境に近付けるために、ディスクイメージ上にはパーティションが作成されている状態を用意できると便利です。そこで、ループバックデバイスを用いてファイルをブロックデバイスとして見せ、fdisk などの対象に取れるようにする方法について説明します。

パーティションを作成する必要がないなら、ディスクイメージに対してmkfsを実行すれば十分なので、この節の内容は不要です。

まず、losetupを用いてファイルをループバックデバイスに結びつけます。この操作にはroot権限が必要です。

# losetup /dev/loop0 FILENAME

losetupに成功すると、/dev/loop0がFILENAMEを内容とするブロックデバイスとして振る舞うようになります。

何らかの理由でloop0が使用中の場合は、適宜loop1などに読みかえてください。

ループバックデバイスに対してfdiskを実行します。後の作業で各パーティションの開始セクタ番号が必要になるので、-uオプションを付けておきます。

# fdisk -u /dev/loop0
Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel
Building a new DOS disklabel with disk identifier 0xaf87fef0.
Changes will remain in memory only, until you decide to write them.
After that, of course, the previous content won't be recoverable.

Warning: invalid flag 0x0000 of partition table 4 will be corrected by w(rite)

パーティションを作成します。この例では一つだけ作ります。

Command (m for help): n
First sector (63-1048575, default 63):
Using default value 63
Last sector or +size or +sizeM or +sizeK (63-1048575, default 1048575):
Using default value 1048575

パーティションを作成したら、状態を確認します。

Command (m for help): p

Disk /dev/loop0: 536 MB, 536870912 bytes
255 heads, 63 sectors/track, 65 cylinders, total 1048576 sectors
Units = sectors of 1 * 512 = 512 bytes
Disk identifier: 0xaf87fef0

      Device Boot      Start         End      Blocks   Id  System
/dev/loop0p1              63     1048575      524256+  83  Linux
Partition 1 does not end on cylinder boundary.

表示される値のうち、「Units」の値(ここでは 512 bytes)と「Start」の値(ここでは63)を覚えておきます。

作成結果に問題なければ変更をイメージに書き戻して終了します。

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.

WARNING: Re-reading the partition table failed with error 22: Invalid argument.
The kernel still uses the old table.
The new table will be used at the next reboot.
Syncing disks.
Command (m for help): q

使いおわったらループバックデバイスを開放します。

# losetup -d /dev/loop0
イメージ内のパーティションをフォーマット

ここまでの作業でディスクイメージにパーティションを作成できましたが、まだ個々のパーティションにはファイルシステムが書かれていません。個別のパーティションに対してmkfsを実行するための手順を説明します。

mkfsの対象とするためには、(ディスクイメージ全体ではなく)対象となるパーティションの部分を取り出す必要があります。

losetupの-oオプションを使用することで、ファイルの途中からをループバックデバイスに結びつけます。

先ほどの例では 開始位置が 63、Unit が 512 bytes だったので、パーティション#1のオフセットとして63*512=32256バイトを設定します。

# losetup -o 32256 /dev/loop0 FILENAME

losetupに成功したら、好みのファイルシステムを作成できます。

# mkfs.ext2 /dev/loop0

使いおわったらループバックデバイスを開放します。

# losetup -d /dev/loop0

イメージ内のパーティションに外からアクセス

既にファイルシステムが作られているイメージ(上記の手順で作成したものや、仮想環境で使っていたrawイメージなど)を扱う場合、mountの"loop"オプションを使用することで、イメージ内部のパーティションを直接ホスト環境にマウントすることができます。

この例の場合、loopのoffsetに開始位置(32256)を指定する:

# mount -o loop,offset=32256 FILENAME /mnt/

と、/mnt経由で先ほど作成したパーティションの内容を操作することができるようになります。

作業が終わったら通常のmountと同じように

# umount /mnt/

します。

注意

仮想環境で使用中のイメージファイルをホスト側環境から同時に操作すると、データを失う可能性があります。

sysfs 経由でモジュールパラメータにアクセス

Posted by Seiichi SATO

sysfs経由でモジュールパラメータにアクセスする方法を紹介します。

Linux-2.6でモジュールパラメータを定義するマクロがMODULE_PARMからmodule_paramに変更されました。

Linux-2.4のMODULE_PARM:

/* パラメータparamをint型で宣言 */
static int param = 0;
MODULE_PARM(param, "i");
MODULE_PARM_DESC(param, "Description");

Linux-2.6のmodule_param:

/* パラメータparamをint型で宣言 */
static int param = 0;
module_param(param, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(param, "Description");

insmodの引数として指定できるパラメータであることは同じですが、module_paramではsysfsからもパラメータにアクセスできます。

# echo 1 > /sys/module/モジュール名/parameters/param

似たようなことはprocfsでもできますが面倒です。module_paramであればsysfsの詳細を知らなくても定義するだけでモジュール内の変数をパラメータとしてユーザ空間にexportできます。デバッグ時など、ioctlを使うまでもない場合には便利じゃないでしょうか?

モジュールではなくカーネルにstaticリンクされててもアクセスできます。

sysfsによってファイルとして見えるパラメータのパーミッションはmodule_paramの引数で指定します。

パラメータとして使う変数が文字列の場合、module_param_string を使います。

関連記事

Linux 起動ロゴの変更

Posted by Seiichi SATO

フレームバッファに表示される起動時のロゴ画像を変更する方法を紹介します。

screenshot (fdo_logo_screenshot.jpg)

以前はピクセル値が配列にベタ書きされたヘッダファイルを用意する必要がありましたが、Linux-2.6でフレームバッファ周辺が書き直されて PNM を直接ソースツリーに置けるようになりました。

ロゴ画像 (fdo_logo.png)

例として、このfreedesktop.orgのロゴ画像 (PNG, 80x80) を224色の起動ロゴにしてみます。

まず、画像をPNMに変換します。

$ convert -colors 224 fdo_logo.png fdo_logo.pnm

pnm2ascで ピクセル値がASCIIのPNMに変換して、drivers/video/logo/ に放り込みます。

$ pnm2asc fdo_logo.pnm > drivers/video/logo/logo_fdo_clut224.ppm

drivers/video/logo/Makefileに以下を追加します。

obj-$(CONFIG_LOGO_FDO_CLUT224) += logo_fdo_clut224.o

drivers/video/logo/Kconfig に以下を追加します。

config LOGO_FDO_CLUT224
        bool "224-color freedesktop.org logo"
        depends on LOGO
        default y

drivers/video/logo/logo.cに追加したロゴ画像のプロトタイプ宣言を加えます。

extern const struct linux_logo logo_fdo_clut224;

drivers/video/logo/logo.c:fb_find_logo()のif (depth >=4) { } の最後に以下を追加します。

#ifdef CONFIG_LOGO_FDO_CLUT224
logo = &logo_fdo_clut224;
#endif

あとは、CONFIG_LOGO_FDO_CLUT224=yでカーネルをリビルドするだけです。

drivers/video/logo/{Makefile,Kconfig,logo.c}を弄りたくなければ、既存のロゴを上書きするだけでもいいと思います。

top
[0] ホーム
[4] 記事一覧
© 2010 Pylone
会社概要 | プライバシー