[Subject Prev][Subject Next][Thread Prev][Thread Next][Subject Index][Thread Index]

[linux-users:99771] Re: lsコマンドの表示について(ディレクトリのサイズ)


楠根です。

きっと回答はあっちこっちから投稿されるでしょうし、

In Subject: [linux-users:99764] lsコマンドの表示について(ディレクトリのサイズ)
    "Toshiaki Maeda" <maeda _at_ auc.co.jp> wrote:

 >> かなり基本的なことかもしれませんが、どうしても調べることが
 >> できないので、皆様お知恵をお貸し願えますでしょうか。

ということなので、

 >> lsコマンドを使うときに「-l 」オプションをつけますと、
 >> ディレクトリ内のファイルなどの詳細表示がでますよね(当たり前ですが・・・)。
 >> このときにディレクトリの行にはファイルサイズが4096の倍数で
 >> 表示されている(あるいは別の数字の倍数?)と思いますが、
 >> これには何らかの意味があるのでしょうか。

という質問について、答はだいたい推測はできますけど、
私がさっき自分の環境で実際にどう確認してみたか書いてみますね。
一応答は書いてますが、そこに至るまで非常に長いので暇な時にどうぞ。
あ、C がちょっとくらい読めることはなんとなく前提にしてます。
# 環境は rawhide-20030410 ベースで kernel-2.4.20-1.1963 です。


まず、調べる内容ですが、
どの directory もサイズが 4096 の倍数ということから、
新しく directory を作るところをおいかけてみることにします。

新しく directory を作るといえば mkdir、
おいかけるといえば strace または ltrace なので、
mkdir コマンドに ltrace と strace をかけてみます。

  [kusune _at_ kokone kusune]$ ltrace mkdir a
  __libc_start_main(0x08048f10, 2, 0xbfffe614, 0x0804b8d0, 0x0804b900 <unfinished ...>
  ...中略...
  getopt_long(2, 0xbfffe614, "pm:v", 0x0804bac0, NULL) = -1
  umask(00)                                        = 022
  umask(022)                                       = 00
  mkdir("a", 0777)                                 = 0
  exit(0 <unfinished ...>
  __fpending(0x40152d80, 0, 13, 0x08048748, 0x400282d4) = 0
  +++ exited (status 0) +++
  [kusune _at_ kokone kusune]$ rmdir a
  [kusune _at_ kokone kusune]$ strace mkdir a
  execve("/bin/mkdir", ["mkdir", "a"], [/* 31 vars */]) = 0
  ...中略...
  brk(0x804f000)                          = 0x804f000
  umask(0)                                = 022
  umask(022)                              = 0
  mkdir("a", 0777)                        = 0
  exit_group(0)                           = ?
  [kusune _at_ kokone kusune]$ 

とゆーわけで、どうも mkdir コマンドは実行のための初期化と後始末以外は
mkdir システムコールを呼んでだけっぽいということが確認できます。


システムコールは、kernel がユーザプロセスのために用意したプログラム
インタフェースなので、当然実際の定義は kernel source の中にあります。
ですから、次は kernel の source 内を探ります。

システムコールはほぼシステムコール名の頭に sys_ をつけた関数として
include/linux/syscall.h で定義されているので、sys_mkdir() を探します。
mkdir はファイルシステム関連の処理なので fs/ 以下を grep で探すと、

  [kusune _at_ kokone fs]$ grep sys_mkdir *.c
  namei.c:asmlinkage long sys_mkdir(const char * pathname, int mode)
  [kusune _at_ kokone fs]$ 

実体は namei.c にありました。
# 別に find + xargs とかで全部探してもいいですけど。

ところが、実際に見てみましたが、サイズが 30 行くらいしかありません。
内容も、一見ややこしそうですが、どうも半分くらいは初期化と後始末です。
呼ばれている関数名や使われている変数の名前から類推するに、
ユーザプロセスに渡された pathname を inode と directory entry に
変換して vfs_mkdir() に渡してるだけのようです。
そのあとは一時領域の解放とか変更内容の書き込みとかの後始末っぽいですね。

vfs_mkdir() は直前に定義されていたので、今度はこちらを見てみます。
が、今度はもっと小さく 20 行程度しかなく、しかも今度もまんなかあたりで
dir->i_op->mkdir() という関数がポインタ経由で呼び出されています。


実は、Linux の(ディレクトリも含む)ファイルアクセスは、
Linux のサポートするさまざまなファイルシステムを統合的に扱うため、
VFS (Virtual File System または Virtual Filesystem Switch) という
抽象化機構を持っています。

VFS では、全てのファイルを directory entry と inode で管理します。
VFS ではファイルアクセスを抽象化されたいくつかのメソッドとして定義し、
各ファイルシステムはそのメソッドに対応した実際の処理を実装します。
この、各メソッドに対応する実際の処理をする関数が登録されているのが
inode 情報に含まれる struct inode_operations 型の i_op メンバなのです。
# struct inode_operations は include/linux/fs.h で定義されています。
# 詳しくは
#   http://www.atnf.csiro.au/people/rgooch/linux/vfs.txt
#   http://www.linux.or.jp/JF/JFdocs/Linux-Kernel-Internals-3.html
# などをどうぞ。

fs/ 直下にあるのは実は VFS レベルの処理で、
各ファイルシステム依存の実際の処理は各 sub directory 以下にあります。


vfs_mkdir() は実際には各ファイルシステムの mkdir メソッド用の関数を
呼んでいることがわかったので、次はファイルシステムごとの処理を見ます。
今回は一般的な例が知りたいのだと思うので、
私の環境で標準で使っている ext3 filesystem を調べてみます。

とりあえず、ext3 用の inode_operations の定義を探るべく、
include/linux 以下の ext3 関連の include file を grep してみると、

  [kusune _at_ kokone linux]$ grep inode_operations ext3_*.h
  ext3_fs.h:extern struct inode_operations ext3_file_inode_operations;
  ext3_fs.h:extern struct inode_operations ext3_dir_inode_operations;
  ext3_fs.h:extern struct inode_operations ext3_fast_symlink_inode_operations;
  [kusune _at_ kokone linux]$ 

というように三つの構造体があるようです。

実際の定義を探して fs/ext3/ 以下を探ると、

  [kusune _at_ kokone ext3]$ grep 'struct inode_operations' *.c
  file.c:struct inode_operations ext3_file_inode_operations = {
  namei.c:struct inode_operations ext3_dir_inode_operations = {
  symlink.c:struct inode_operations ext3_fast_symlink_inode_operations = {
  [kusune _at_ kokone ext3]$ 

とそれぞれみつかりました。実際に見てみると、

  struct inode_operations ext3_file_inode_operations = {
      truncate:    ext3_truncate,  /* BKL held */
      setattr:     ext3_setattr,   /* BKL held */
  };


  struct inode_operations ext3_dir_inode_operations = {
      create:      ext3_create,    /* BKL held */
      lookup:      ext3_lookup,    /* BKL held */
      link:        ext3_link,      /* BKL held */
      unlink:      ext3_unlink,    /* BKL held */
      symlink:     ext3_symlink,   /* BKL held */
      mkdir:       ext3_mkdir,     /* BKL held */
      rmdir:       ext3_rmdir,     /* BKL held */
      mknod:       ext3_mknod,     /* BKL held */
      rename:      ext3_rename,    /* BKL held */
  };

  struct inode_operations ext3_fast_symlink_inode_operations = {
      readlink:    ext3_readlink,      /* BKL not held.  Don't need */
      follow_link: ext3_follow_link,   /* BKL not held.  Don't need */
  };

というように、
ext3_dir_inode_operations にしか mkdir メソッドが定義されていません。
directory にしか directory は作れないのであたり前といえばあたり前です。


mkdir メソッドに対応するのは ext3_mkdir() だということがわかったので、
実際にこの関数を調べてみます。

  namei.c:static int ext3_mkdir(struct inode * dir, struct dentry * dentry, int mode)
  namei.c:    mkdir:      ext3_mkdir,     /* BKL held */
  [kusune _at_ kokone ext3]$ 

というわけで、namei.c にありました。上から順に見ていくと、

    inode = ext3_new_inode (handle, dir, S_IFDIR);

という行で新しく inode を作成したあと、

    inode->i_op = &ext3_dir_inode_operations;
    inode->i_fop = &ext3_dir_operations;
    inode->i_size = inode->u.ext3_i.i_disksize = inode->i_sb->s_blocksize;

というところで初期化しています。
i_size というのは inode 構造体の中で inode の実際の size を保存する
メンバなので、どうもここが正体っぽいですね。

include/linux/ext3_fs.h によれば、
i_sb というのは inode の存在する filesystem の superblock 情報、
s_blocksize は superblock 中にある filesystem の blocksize 情報です。

というわけで、
directory を新しく作ると大きさが blocksize になることがわかりました。
4096bytes になってたのは blocksize が 4096bytes だからですね。
# なぜ 4096 なのかは man mke2fs 参照。



いやー疲れました。
実際に調べるのに要したのは 10 分くらいなんですが、
メイル書くのに時間かかりますねーやっぱり。
勢いで書くんじゃなかった…。

ここで調べたのは最初に作成するサイズの根拠だけで、
なぜ大きい directory のサイズも 4096 の倍数になるかは調べてませんが、
同様に新しい file を作成する時の処理を追いかけるとわかると思います。
あとは自力でがんばって下さい。:-)
--
Takeshi Kusune <kusune _at_ sfc.wide.ad.jp>

この情報があなたの探していたものかどうか選択してください。
yes/まさにこれだ!   no/違うなぁ   part/一部見つかった   try/これで試してみる

あなたが探していた情報はどのようなことか、ご自由に記入下さい。特に「まさにこれだ!」と言う場合は記入をお願いします。
例:「複数のマシンからCATV経由でipmasqueradeを利用してWebを参照したい場合の設定について」
Follow-Ups: References: