MC68EZ328 DragonOne SBCでuClinuxを動かす(7) ~rootにmountする~

前回に続いてinitから呼び出されるprepare_namespace()を探ってみます。

prepare_namespace()

ここから先は慎重にみていきます。 ソースはそんなに長くありません。(不要な部分は削っています)

/*
 * Prepare the namespace - decide what/where to mount, load ramdisks, etc.
 */
void prepare_namespace(void)
{
	int is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;
	sys_mkdir("/dev", 0700);
	sys_mkdir("/root", 0700);
	sys_mknod("/dev/console", S_IFCHR|0600, MKDEV(TTYAUX_MAJOR, 1));

	create_dev("/dev/root", ROOT_DEV, NULL);
	if (mount_initrd) {
		if (initrd_load() && ROOT_DEV != MKDEV(RAMDISK_MAJOR, 0)) {
			handle_initrd();
			goto out;
		}
	} else if (is_floppy && rd_doload && rd_load_disk(0))
		ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
	mount_root();
out:
	sys_umount("/dev", 0);
	sys_mount(".", "/", NULL, MS_MOVE, NULL);
	sys_chroot(".");
	mount_devfs_fs ();
}

最初に/dev, /rootのディレクトリを作ります。その次は/dev/consoleのデバイスファイルを作ります。TTYAUX_MAJORは5なので、MAJOR=5, MINOR=1のデバイスファイルです。

ここでUbuntuで試しにmountしたromfsの/dev/consoleをみてみると、MAJOR=5, MINOR=1となっていたので一致しています。

mc68ez328_dragonone_sbc_uclinux_part7_dev_console.png

create_dev()

次にcreate_dev()で/dev/rootのデバイスファイルを作ります。この関数はinit/do_mount.cにあります。

static int __init create_dev(char *name, kdev_t dev, char *devfs_name)
{
	void *handle;
	char path[64];
	int n;

	sys_unlink(name);
	if (!do_devfs)
		return sys_mknod(name, S_IFBLK|0600, kdev_t_to_nr(dev));
 :
}

ここでは、DEVFSは使用しない設定になっているので、do_devfsはFALSEです。そのため、sys_mknodで/dev/rootのデバイスファイルを作るだけで、prepare_namespace()にもどります。

prepare_namespace()にもどったあと、mount_initrdの部分やフロッピィディスクの部分は該当しないので素通りして、続いての関数はmount_root()になります。

mount_root()

まさにここでrootディレクトリがmountされるのでしょうか。関数をみてみます。

static void __init mount_root(void)
{
	devfs_make_root(root_device_name);
	create_dev("/dev/root", ROOT_DEV, root_device_name);
	mount_block_root("/dev/root", root_mountflags);
}

たった3行しかありません。しかもdevfsは使わないので、devfs_make_root()はそのままリターンで戻ってきます。次に再びcreate_dev()です。さっきも実行したのですが、今度はroot_device_nameに値が入っています。しかし、devfsは使わないのでこの情報は特に使われず、/dev/rootをunlinkしたあとにsys_mknod()が行われ、再び/dev/rootのデバイスファイルができます。

mount_block_root()

次の関数はmount_block_root()です。この関数をみてみます。

static void __init mount_block_root(char *name, int flags)
{
	char *fs_names = __getname();
	char *p;

	get_fs_names(fs_names);
retry:
	for (p = fs_names; *p; p += strlen(p)+1) {
		int err = sys_mount(name, "/root", p, flags, root_mount_data);
		switch (err) {
			case 0:
				goto out;
			case -EACCES:
				flags |= MS_RDONLY;
				goto retry;
			case -EINVAL:
		        case -EBUSY:
				continue;
		}
	        /*
		 * Allow the user to distinguish between failed open
		 * and bad superblock on root device.
		 */
		printk ("VFS: Cannot open root device \"%s\" or %s\n",
			root_device_name, kdevname (ROOT_DEV));
		printk ("Please append a correct \"root=\" boot option\n");
		panic("VFS: Unable to mount root fs on %s",
			kdevname(ROOT_DEV));
	}
	panic("VFS: Unable to mount root fs on %s", kdevname(ROOT_DEV));
out:
	putname(fs_names);
	sys_chdir("/root");
	ROOT_DEV = current->fs->pwdmnt->mnt_sb->s_dev;
	printk("VFS: Mounted root (%s filesystem)%s.\n",
		current->fs->pwdmnt->mnt_sb->s_type->name,
		(current->fs->pwdmnt->mnt_sb->s_flags & MS_RDONLY) ? " readonly" : "");
}

sys_mount()で/dev/rootデバイスを/rootファイルシステムにmountしているように見えます。fs_namesでループしていますが、これはどのファイルシステムを使うかを試しているようです。私が仕込んだデバックログでは以下のように表示されました。

mount_root:mount_block_root(/dev/root) root_mountflags=32769
get_fs_names() fs_names=/dev/root
get_fs_names() errno=0
sys_mount(): name=/dev/root p=ext2 flags=32769 root_mount_data=
sys_mount(): errno=0 err=-22  ※ext2ではなかった
sys_mount(): name=/dev/root p=romfs flags=32769 root_mount_data=
sys_mount(): errno=0 err=0    ※romfsと認識
putname() fs_names=ext2
putname() errno=0
sys_chdir(/root) errno=0
VFS: MAJOR=31, MINOR=0
VFS: Mounted root (romfs filesystem) readonly.
mount_root:mount_block_root(/dev/root) errno=0

putname()でext2を指定していますが、この実体はkmem_cache_free()なので使わないキャッシュを開放しているようです。そのあとにsys_chdir()で/rootにカレントディレクトリを移動しています。

その後rootにマウントが完了したというメッセージが表示されます。

VFS: Mounted root (romfs filesystem) readonly.

最後の仕上げ

mount_root()から戻ってきた後は、最後の仕上げとしてカレントディレクトリを/にします。

まずは、sys_umount("/dev", 0);で、/devをumountします。その後カレントディレクトリを/にmountします。

そのあと、sys_chroot(".");でカレントディレクトリをルートディレクトリに変更します。これでromfsがルートにmountされます。その後、mount_devfs_fs()がありますが、devfsは使っていないのですぐリターンしてきます。

           :
	mount_root();
out:
	sys_umount("/dev", 0);
	sys_mount(".", "/", NULL, MS_MOVE, NULL);
	sys_chroot(".");
	mount_devfs_fs ();
}

以上で、prepare_namespace()は終わりです。再びinitに戻ります。

おかしなところが見当たらない

ここまでのステップでは私が組み込んだデバックログにエラーはみあたりません。

mc68ez328_dragonone_sbc_uclinux_part7_mount_root_msg2.png

mount_root()が終わった時点でromfsが/rootにmountできているように見え、その後ルートディレクトリにmountされているように見えるのですが。(続く)

前へ

MC68EZ328 DragonOne SBCでuClinuxを動かす(6) ~initスレッドを追う~

次へ

MC68EZ328 DragonOne SBCでuClinuxを動かす(8) ~ハードウェアを再確認する~