メモ

何か色々な意味でとっちらかっててメモにさえなっとらん。スデに控えてるかもしれない部分含め以下に。

とりあえず

statfs がどの属性を使ってるかを控えてない模様。ええと sys_statfs() の定義は fs/open.c にて以下。

asmlinkage long sys_statfs(const char __user * path, struct statfs __user * buf)
{
	struct nameidata nd;
	int error;

	error = user_path_walk(path, &nd);
	if (!error) {
		struct statfs tmp;
		error = vfs_statfs_native(nd.dentry, &tmp);
		if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
			error = -EFAULT;
		path_release(&nd);
	}
	return error;
}

vfs_statfs_native() を掘ってみる。同様に fs/open.c にて以下に一部のみ。

static int vfs_statfs_native(struct dentry *dentry, struct statfs *buf)
{
	struct kstatfs st;
	int retval;

	retval = vfs_statfs(dentry, &st);
	if (retval)
		return retval;

この後、st 側から buf 側にコピーする処理が書いてある。vfs_statfs() な戻りは 0 が normal なので上記末端は不具合時の分岐になるのか。
ちなみに以下が肝心な部分と思われる。man statfs によれば f_blocks 属性が_ファイルシステムの総ブロック数_との事。

		buf->f_bsize = st.f_bsize;
		buf->f_blocks = st.f_blocks;

次に vfs_statfs() を掘ってみると定義は同様に fs/open.c で以下。

int vfs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
	int retval = -ENODEV;

	if (dentry) {
		retval = -ENOSYS;
		if (dentry->d_sb->s_op->statfs) {
			memset(buf, 0, sizeof(*buf));
			retval = security_sb_statfs(dentry);
			if (retval)
				return retval;
			retval = dentry->d_sb->s_op->statfs(dentry, buf);
			if (retval == 0 && buf->f_frsize == 0)
				buf->f_frsize = buf->f_bsize;
		}
	}
	return retval;
}

タブが微妙ですがご勘弁下さい。結局ファイルシステムの statfs 属性が呼ばれる模様。ext3 の struct super_operations の statfs 属性には ext3_statfs() な関数ポインタが設定されている。
という事で fs/ext3/super.c を見てみると、簡単に考えてたんですが理解が全然だった事が判明。ってか、s_blocksize がソレにあたる、という大誤読あり。あり得ん。
とりあえず核心は以下みたいなんですが

	buf->f_blocks = le32_to_cpu(es->s_blocks_count) - overhead;

このあたりもう少しきっちり確認必要。先頭から。

static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf)
{
	struct super_block *sb = dentry->d_sb;
	struct ext3_sb_info *sbi = EXT3_SB(sb);
	struct ext3_super_block *es = sbi->s_es;
	ext3_fsblk_t overhead;
	int i;
	u64 fsid;

引数で頂いた struct dentry な領域の d_sb 属性を super block として取り出して EXT3_SB というマクロでファイルシステム固有のデータが格納される s_fs_info 属性を取り出している模様。定義が以下のはず。

static inline struct ext3_sb_info * EXT3_SB(struct super_block *sb)
{
	return sb->s_fs_info;
}

で、struct ext3_sb_info 構造体なメンバの s_es を取り出している。属性定義は以下な模様 (include/linux/ext3_fs_sb.h)。

	struct ext3_super_block * s_es;	/* Pointer to the super block in the buffer */

で、この ext3_super_block な s_blocks_count 属性がそれにあたる、と。ただ、処理にあたって overhead を引いた値を f_blocks 属性に格納してますな。とりあえず overhead の準備を確認。

	if (test_opt (sb, MINIX_DF))
		overhead = 0;
	else {

な分岐あり。test_opt はマクロで include/linux/ext3_fs.h にて定義。

#define test_opt(sb, opt)		(EXT3_SB(sb)->s_mount_opt & \
					 EXT3_MOUNT_##opt)

これどう展開されるか、というと以下なカンジ?

        if (EXT3_SB(sb)->s_mount_opt & EXT3_MOUNT_MINIX_DF)

EXT3_MOUNT_MINIX_DF は直上で定義されてて以下。

#define EXT3_MOUNT_MINIX_DF		0x00080	/* Mimics the Minix statfs */

struct ext3_sb_info の s_mount_opt 属性って_マウントオプション_となっている。ここのビットが立ってたら overhead は 0 なのか。とりあえず細かいナニは一旦スルーで s_blocks_count で grep してみるか。このあたり、別途色々確認予定です。