理想未来ってなんやねん

娘可愛い。お父さん頑張る。

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関数について見ていきます。