tmpfs_mount関数のソースコードを読む(後半)
tmpfs_mount関数のコードを昨日の続きから見ていきます。
/* Allocate the tmpfs mount structure and fill it. */ tmp = (struct tmpfs_mount *)malloc(sizeof(struct tmpfs_mount), M_TMPFSMNT, M_WAITOK | M_ZERO);
見たままですがtmpfs_mount構造体分の領域をmallocで確保しています。
mtx_init(&tmp->allnode_lock, "tmpfs allnode lock", NULL, MTX_DEF); tmp->tm_nodes_max = nodes; tmp->tm_nodes_inuse = 0; tmp->tm_maxfilesize = (u_int64_t)(cnt.v_page_count + get_swpgtotal()) * PAGE_SIZE; LIST_INIT(&tmp->tm_nodes_used);
mtx_init関数はその名の通りミューテックスの初期化を行っています。
tm_nodes_max、tm_nodes_inuse、tm_maxfilesizeは見たままなので割愛します。
get_swpgtotal関数はfs/tmpfs/tmpfs_vfsops.cで定義されていますが、今回は中まで追いません。
名前から推察し処理はスワップページのトータルサイズを取得していると思います。
LIST_INITマクロはsys/queue.hで次の通り定義されています。
#define LIST_FIRST(head) ((head)->lh_first) #define LIST_INIT(head) do { \ LIST_FIRST((head)) = NULL; \ } while (0)
tmp->tm_nodes_used->lh_firstにNULLを代入しているだけのようです。
tmp->tm_pages_max = pages; tmp->tm_pages_used = 0; tmp->tm_ino_unr = new_unrhdr(2, INT_MAX, &tmp->allnode_lock);
tm_pages_max、tm_pages_usedは見たままです。
new_unrhdr関数は新しいユニット番号アロケータのエンティティを初期化しています。
tmp->tm_dirent_pool = uma_zcreate("TMPFS dirent", sizeof(struct tmpfs_dirent), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); tmp->tm_node_pool = uma_zcreate("TMPFS node", sizeof(struct tmpfs_node), tmpfs_node_ctor, tmpfs_node_dtor, tmpfs_node_init, tmpfs_node_fini, UMA_ALIGN_PTR, 0);
uma_zcreate関数は、ゾーンアロケータのゾーンを新たに作成する関数です。
ゾーンアロケータは、メモリ確保、開放の他にリソースの確保、開放といった管理の為のインターフェースも提供します。
uma_zcreate関数で作成したゾーンからメモリを割り当てる場合はuma_zalloc関数を使用し、開放の場合はuma_zfree関数で開放を行います。
また、uma_zcreate関数で作成したゾーンの破壊はuma_zdestroy関数で行います。
tmpfs_node_ctor、tmpfs_node_dtor、tmpfs_node_init、tmpfs_node_finiはコールバックで呼ばれる関数のポインタです。
tmpfs_node_ctor、tmpfs_node_dtorはノードのコンストラクタとデストラクタで、uma_zalloc関数およびuma_zfree関数内で呼び出されます。
tmpfs_node_init、tmpfs_node_finiは、それぞれイニシャライザとファイナライザで、関数内部でミューテックスの初期化と解放を行っています。
/* Allocate the root node. */ error = tmpfs_alloc_node(tmp, VDIR, root_uid, root_gid, root_mode & ALLPERMS, NULL, NULL, VNOVAL, &root); if (error != 0 || root == NULL) { uma_zdestroy(tmp->tm_node_pool); uma_zdestroy(tmp->tm_dirent_pool); delete_unrhdr(tmp->tm_ino_unr); free(tmp, M_TMPFSMNT); return error; }
tmpfs_alloc_node関数によりrootノードを確保しています。
tmpfs_alloc_node関数は、fs/tmpfs/tmpfs_subr.cで定義されています。
ルートノードの確保に失敗した場合は、初期化したゾーンアロケータおよびユニット番号アロケータを破壊し、メモリを開放しエラーを返しています。
KASSERT(root->tn_id == 2, ("tmpfs root with invalid ino: %d", root->tn_id)); tmp->tm_root = root;
rootノードのチェック。
先程ユニット番号アロケータの最小値を2で初期化しました。
rootノードは最初に確保されるため、idが2以外の場合は不正な値としてKASSERTで終了します。
問題ない場合は、rootノードとしてtmpfs_mount構造体のtm_rootに保存しています。
MNT_ILOCK(mp); mp->mnt_flag |= MNT_LOCAL; mp->mnt_kern_flag |= MNTK_MPSAFE; MNT_IUNLOCK(mp);
フラグをセットしています。
定数MNT_LOCALおよび定数MNTK_MPSAFEはsys/mount.hで定義されています。
MNT_LOCALによりローカルストレージであると指定しています。ネットワークストレージであるsmbfsおよびnfsではMNT_LOCALがセットされません。
また、MNTK_MPSAFEによりマルチプロセッサセーフであると指定しています。
mp->mnt_data = tmp; mp->mnt_stat.f_namemax = MAXNAMLEN; vfs_getnewfsid(mp); vfs_mountedfrom(mp, "tmpfs"); return 0;
初期化したtmpfs_mount構造体変数をmnt_dataにセットしています。
vfs_getnewfsid関数でに新しいファイルシステム識別子を割り付け、
最後にvfs_mountedfrom関数によってマウント情報を設定しています。
明日はtmpfs_unmount関数について見ていきます。