試験運用中なLinux備忘録・旧記事

はてなダイアリーで公開していた2007年5月-2015年3月の記事を保存しています。

読み取るだけのファイルやディレクトリを圧縮しつつ、無圧縮時と同様に扱う(概要と準備)

複数のファイルやディレクトリを圧縮すると、その中にあるデータにアクセスするためには、一度それをどこかに展開する必要のある場合が多い*1
もし、圧縮したいデータが読み取りしかしていないものであれば、読み取り専用の圧縮ファイルシステムにデータを圧縮し、それをマウントするという形をとることで、(多少手間はかかるが)ディスク領域を節約しつつ、圧縮前と同じ感覚で中のデータを開くことができる。

圧縮の対象について

まず、圧縮の基本として、圧縮済みファイル形式(GIF,JPEG,PNGなどの画像、MP3,Vorbis,FLAC,TTA,WMAなどのオーディオ、MPEG,DivX,Xvid,WMVなどのビデオ、などと、挙げていくときりがない)は、それ以上圧縮をかけてもほとんど縮まない。圧縮ファイル(7z,bzip2,gzip,zipなど)も同様だが、圧縮ファイルシステムに圧縮ファイルを入れる意味はあまりない気がする。
これを踏まえた上で、内容を上書きすることのないデータを圧縮の対象とする。以下は有効となりそうな例。

  • アプリケーションの実行ファイル。OpenOffice.orgの場合、かなりのディスク容量を食うが、圧縮が結構効くので、全体を圧縮すると、かなりのディスク容量が節約できる。しかし、その他多くの/usr/bin/以下の実行ファイルなどに対しては、運用上、圧縮ファイルシステムを使うことができない。
  • テキストデータ。データの性質上、縮みやすいが、編集して上書きすることのないものに限られる。また、bzip2圧縮したテキストファイルは、アプリケーションが読み込み時に展開し、保存時に圧縮を自動的に行ってくれるもの(例: Emacs 22)もあり、テキスト圧縮に読み込み専用ファイルシステムが必ずしもふさわしいとは、一概には言えない。ソフトウェアが吐き出す記録(ログ)ファイルをまとめて圧縮するという使い方は有効と思われる
  • CDのイメージファイル。元々のサイズが大きく、節約できる容量も大きい。注意点として、中に圧縮済みデータがある場合はあまり縮まない。特に、GNU/LinuxのLiveCDは、既にcloop*2Squashfsといった読み取り専用ファイルシステムで圧縮された状態でCDの容量いっぱいになっていて、圧縮の余地がほとんどないため、効果が薄い
  • 特殊なオーディオ形式。タグ情報の編集などを後から行うことはできないが、ほとんどの場合は聴くために読み出すだけなのでメリットがあり、形式によっては結構縮むものもある
  • 画像や音声などのうち、無圧縮の状態で保管したいがディスク容量は節約したいとき。ただし、音声データの場合、TTA形式にエンコードすると短時間でバランスのよい可逆圧縮ができるので、無圧縮WAVで保管したい理由がなければそちらのほうがよいかも

読み取り専用圧縮ファイルシステムの選択

色々な種類の読み取り専用圧縮ファイルシステムが存在するが、以下の2つを取り上げる。軽さを取るならSquashfs、容量を取るならCromfsと使い分けるのも手。

Squashfs: http://squashfs.sourceforge.net/

圧縮率と速度のバランスがよく、おすすめ。

  • 高速に動作
  • 安定して動作している実績がある
  • そこそこの圧縮率(zlibのdeflateで圧縮、inflateで展開)*3
  • カーネルドライバでアクセスするが、kernel.orgがリリースする、パッチの適用されていない状態のカーネル(「Vanillaカーネル」や「素のカーネル」とも呼ばれる)のソースツリーには、バージョン2.6.22の時点では含まれていないため、ソースツリーにパッチを当ててカーネルをビルドする必要がある*4

(2009/3/25)Squashfsはバージョン2.6.29のカーネルからは標準で含まれるようになっている。そのため、独自にパッチを当てたりする必要はない。ただ、それまでのバージョンでもディストリのカーネルを使用している場合はディストリがパッケージを用意していたりすることが多かったので、ユーザにはあまり影響はないかもしれない。

Cromfs: http://bisqwit.iki.fi/source/cromfs.html

速度より圧縮率優先のケースにおいて有用。スペックの低いマシンでは厳しいかも(特にメモリ)。
カーネルが標準でサポートしている「Cramfs」とは別物

  • 7-ZipLZMAアルゴリズムの使用により、圧縮率が非常に高い(が、圧縮は極めて低速。とにかく遅い。これらの特徴はSquashfs-LZMAでも同様)
  • ユーザスペースドライバでアクセスし、カーネルFUSEサポートとFUSEライブラリが必要だが、カーネルにパッチを当てたり再ビルドしたりする必要がなく、一般ユーザ権限でインストールからマウントまでが可能

DebianUbuntuのディストリ付属カーネルSquashfsを使う

Debian lenny(2007年8月末時点)では、

のようなパッケージ名で、ディストリ付属カーネルに向けた、Squashfsコンパイル済みカーネルモジュールが提供されているので、CPUアーキテクチャに合ったパッケージをインストールする。
Ubuntu feisty(7.04)では、「squashfs-source」というパッケージをインストールすることで、/usr/src/squashfs.tar.bz2というソースファイルが置かれるので、これを展開してインストールしようとしたのだが失敗。

$ cd /tmp/
$ tar jxf /usr/src/squashfs.tar.bz2
$ cd modules/squashfs/
$ make
make -C /lib/modules/`uname -r`/build SUBDIRS=`pwd`/linux-2.6 CONFIG_SQUASHFS=m \
                 CC="gcc" modules
make[1]: ディレクトリ `/usr/src/linux-headers-2.6.20-16-generic' に入ります
  CC [M]  /tmp/modules/squashfs/linux-2.6/inode.o
/tmp/modules/squashfs/linux-2.6/inode.c: In function ‘squashfs_iget’:
/tmp/modules/squashfs/linux-2.6/inode.c:607: error: ‘struct inode’ has no member named ‘i_blksize’
/tmp/modules/squashfs/linux-2.6/inode.c:660: error: ‘struct inode’ has no member named ‘i_blksize’
/tmp/modules/squashfs/linux-2.6/inode.c: トップレベル:
/tmp/modules/squashfs/linux-2.6/inode.c:2103: 警告: ‘kmem_cache_t’ is deprecated
/tmp/modules/squashfs/linux-2.6/inode.c: In function ‘squashfs_alloc_inode’:
/tmp/modules/squashfs/linux-2.6/inode.c:2109: error: ‘SLAB_KERNEL’ undeclared (first use in this function)
/tmp/modules/squashfs/linux-2.6/inode.c:2109: error: (Each undeclared identifier is reported only once
/tmp/modules/squashfs/linux-2.6/inode.c:2109: error: for each function it appears in.)
/tmp/modules/squashfs/linux-2.6/inode.c: トップレベル:
/tmp/modules/squashfs/linux-2.6/inode.c:2122: 警告: ‘kmem_cache_t’ is deprecated
/tmp/modules/squashfs/linux-2.6/inode.c: In function ‘destroy_inodecache’:
/tmp/modules/squashfs/linux-2.6/inode.c:2146: error: void の値が本来の意味通りに無視されませんでした
make[2]: *** [/tmp/modules/squashfs/linux-2.6/inode.o] エラー 1
make[1]: *** [_module_/tmp/modules/squashfs/linux-2.6] エラー 2
make[1]: ディレクトリ `/usr/src/linux-headers-2.6.20-16-generic' から出ます
make: *** [modules] エラー 2

これは本家から最新のパッケージ(squashfs3.2-r2.tar.gz)を落としてLinux 2.6.20用のパッチの中のファイルで置き換えることで解決。Ubuntuのパッケージ側に問題があるようだ(2.6.20以外向けのソースの可能性がある)。

$ cd /tmp/
$ tar jxf /usr/src/squashfs.tar.bz2
$ cd modules/squashfs/linux-2.6/
$ rm * -f
$ patch -f < [squashfs3.2-r2ディレクトリの場所]/kernel-patches/linux-2.6.20/squashfs3.2-patch >/dev/null
$ cd ../
$ make
make -C /lib/modules/`uname -r`/build SUBDIRS=`pwd`/linux-2.6 CONFIG_SQUASHFS=m \
                 CC="gcc" modules
make[1]: ディレクトリ `/usr/src/linux-headers-2.6.20-16-generic' に入ります
  CC [M]  /tmp/modules/squashfs/linux-2.6/inode.o
  CC [M]  /tmp/modules/squashfs/linux-2.6/squashfs2_0.o
  LD [M]  /tmp/modules/squashfs/linux-2.6/squashfs.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /tmp/modules/squashfs/linux-2.6/squashfs.mod.o
  LD [M]  /tmp/modules/squashfs/linux-2.6/squashfs.ko
make[1]: ディレクトリ `/usr/src/linux-headers-2.6.20-16-generic' から出ます
$ sudo make install
make -C /lib/modules/`uname -r`/build SUBDIRS=`pwd`/linux-2.6 CONFIG_SQUASHFS=m \
                 CC="gcc" modules
make[1]: ディレクトリ `/usr/src/linux-headers-2.6.20-16-generic' に入ります
  Building modules, stage 2.
  MODPOST 1 modules
make[1]: ディレクトリ `/usr/src/linux-headers-2.6.20-16-generic' から出ます
install -d /lib/modules/`uname -r`/kernel/fs/squashfs
install -m 644 -c `pwd`/linux-2.6/squashfs.ko /lib/modules/`uname -r`/kernel/fs/squashfs
/sbin/depmod -a

Squashfsカーネルパッチについて

http://sourceforge.net/project/showfiles.php?group_id=63835
からダウンロードできるソースを展開すると、カーネルのバージョンごとのディレクトリがあり、その中のパッチ(*.patch)ファイルを適用する。Squashfs 3.2-r2では、kernel-patches/linux-[バージョン]/ディレクトリの中にsquashfs3.2-patchがある。3.2-r2の中には、Linux 2.6.21と2.6.22のディレクトリが無いが、パッチは正常に適用される。
パッチ当ては、カーネルのソースツリーの一番上の階層(通常/usr/src/linux/)で行う。

$ ls -F
COPYING         MAINTAINERS     arch/     fs/       kernel/  scripts/
CREDITS         Makefile        block/    include/  lib/     security/
Documentation/  README          crypto/   init/     mm/      sound/
Kbuild          REPORTING-BUGS  drivers/  ipc/      net/     usr/

下の例では、Linux 2.6.22のソースツリーに対して2.6.20向けのパッチを適用している。

$ head -n 3 Makefile
VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 22

ここから適用作業。「Hunk #1 succeeded」と出ているのは、適用先の行番号が少しずれているだけで、適用自体に問題はない。

$ sudo patch -p1 < [squashfs3.2-r2ディレクトリの場所]/kernel-patches/linux-2.6.20/squashfs3.2-patch
patching file fs/Kconfig
Hunk #1 succeeded at 1367 (offset -37 lines).
patching file fs/Makefile
Hunk #1 succeeded at 72 (offset 4 lines).
patching file fs/squashfs/inode.c
patching file fs/squashfs/Makefile
patching file fs/squashfs/squashfs2_0.c
patching file fs/squashfs/squashfs.h
patching file include/linux/squashfs_fs.h
patching file include/linux/squashfs_fs_i.h
patching file include/linux/squashfs_fs_sb.h
patching file init/do_mounts_rd.c

カーネル手動ビルド時の設定

カーネルSquashfsサポートを有効にする

Squashfsのパッチが当たっている状態で、これを有効にするには下のように設定する。いずれの項目も、組み込み(*)かモジュール(M)のどちらかを選べる。

Device Drivers  --->
 Block devices  --->
  <*> Loopback device support                     [CONFIG_BLK_DEV_LOOP]

File systems  --->
 Miscellaneous filesystems  --->
 <*> SquashFS 3.2 - Squashed file system support  [CONFIG_SQUASHFS]
Cromfsを使用するために、FUSEサポートを有効にする

Cromfsに限らず、NTFS-3Gなど、FUSEを使用するファイルシステムを使用したい場合に、この項目を組み込みかモジュールにする必要がある。

File systems  --->
<*> Filesystem in Userspace support               [CONFIG_FUSE_FS]

Cromfsのインストール

http://bisqwit.iki.fi/source/cromfs.html#download
から最新の.tar.bz2ファイルをダウンロードする。もし、手元に最新の1つ前のバージョンのソースがある場合、差分(patch-cromfs-[最新の1つ前のバージョン]-[最新バージョン].bz2)も使える。
要件として、FUSEのバージョン2.5.2以降が必要。
インストールは、一般ユーザ権限で行えるようになっていて、install/ディレクトリに実行ファイルとドキュメントが入った状態になる。

$ tar jxf cromfs-1.5.3.1.tar.bz2
$ cd cromfs-1.5.3.1/
$ ./configure
$ make
$ make install
(中略)
*****************************************
The 'install' directory was prepared. Copy the contents to the locations you see
 fit.
*****************************************

中身は以下のとおり。

$ find install/
install/
install/docs
install/docs/size_demo.txt
install/docs/WriteAccess.txt
install/docs/ImplementationGuide.txt
install/docs/BlockIndexing.txt
install/docs/ChangeLog
install/docs/README.html
install/docs/FORMAT
install/progs
install/progs/unmkcromfs
install/progs/mkcromfs
install/progs/cvcromfs
install/progs/cromfs-driver-static
install/progs/cromfs-driver

install/progs/以下の実行ファイルをホームディレクトリの中(例: ${HOME}/bin/)にコピーするなどして使用する。configureスクリプト--prefixオプションを付けたりしても意味はない。

(続く)

関連記事:

*1:アプリケーションとファイルの種類によっては、圧縮ファイルをそのまま開くことができるものがある

*2:KNOPPIXで使用されていることで有名な読み取り専用圧縮ファイルシステムだが、ここでは扱わない

*3:7-ZipLZMA圧縮アルゴリズムを使用するパッチも存在する

*4:Gentoo Linuxでは、Squashfsを含むパッチが当たっている状態のカーネルソースパッケージ(gentoo-sourcesもしくはsuspend2-sources)がインストールできる