読者です 読者をやめる 読者になる 読者になる

minix3.1.4をqemu環境にインスコしたので色々遊ぶ。

minix

というわけで、まずは/usr/src/servers/vm/mmap.cにあるmmapの動作をみてます。
mmapの本体はかなり小さめ。linuxのsys_mmap()も小さいけど中で呼んでるdo_mmap_pgoff()がメインの処理っぽいとも言えると思うけど、minixはほぼdo_mmapで完結してるもよう。

/*===========================================================================*
 *                              do_mmap                                      *
 *===========================================================================*/
PUBLIC int do_mmap(message *m)
{
        int r, n;
        struct vmproc *vmp;
        int mfflags = 0;
        struct vir_region *vr = NULL;

        if((r=vm_isokendpt(m->m_source, &n)) != OK) {
                vm_panic("do_mmap: message from strange source", m->m_source);
        }

        vmp = &vmproc[n];

        if(m->VMM_FLAGS & MAP_LOWER16M)
                printf("VM: warning for %d: MAP_LOWER16M not implemented\n",
                        m->m_source);

        if(!(vmp->vm_flags & VMF_HASPT))
                return ENXIO;

        if(m->VMM_FD == -1 || (m->VMM_FLAGS & MAP_ANON)) {
                int s;
                vir_bytes v;
                u32_t vrflags = VR_ANON | VR_WRITABLE;
                size_t len = (vir_bytes) m->VMM_LEN;

                if(m->VMM_FD != -1) {
                        return EINVAL;
                }

                if(m->VMM_FLAGS & MAP_CONTIG) mfflags |= MF_CONTIG;
                if(m->VMM_FLAGS & MAP_PREALLOC) mfflags |= MF_PREALLOC;
                if(m->VMM_FLAGS & MAP_ALIGN64K) vrflags |= VR_PHYS64K;

                if(len % VM_PAGE_SIZE)
                        len += VM_PAGE_SIZE - (len % VM_PAGE_SIZE);

                if(!(vr = map_page_region(vmp,
                        arch_vir2map(vmp, vmp->vm_stacktop), VM_DATATOP, len, MAP_NONE,
                        vrflags, mfflags))) {
                        return ENOMEM;
                }
        } else {
                return ENOSYS;
        }

        /* Return mapping, as seen from process. */
        vm_assert(vr);
        m->VMM_RETADDR = arch_map2vir(vmp, vr->vaddr);

        return OK;
}

この関数を見てて気づいたのは、"m->VMM_FD == -1"が2ヶ所出現して、そのうちの1個はEINVALを返すパターンになってるということと、
↓のif文の条件に該当しないとENOSYSを返しているってところ。

if(m->VMM_FD == -1 || (m->VMM_FLAGS & MAP_ANON)) {
 中略
} else {
    return ENOSYS;
}

ここから察するにminix3.1.4のmmapは・・・
1.アノニマスmmapのみサポートしている
2.MAP_ANONを使う場合はfdは-1にしないといけない
ということっぽい。

そんな分けで、ちょっとしたテストを。。。
#munmap()呼んでないけど、コンパイル時にmunmapが定義されていないとかエラーが出たので呼んでません。
#テストプログラムだし別に良いやってことでwww

#include <stdio.h>
#include <sys/mman.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

static void print_result(char *name, int ret)
{
        printf("test %s was %s(errno is %d)\n", name, (ret == 0) ? "succeed" : "failed", ret);
}

static int do_mmap_test(int fd, int flg)
{
        void *p;
        errno = 0;

        p = mmap(NULL, 1024, PROT_READ | PROT_WRITE, flg, fd, 0);

        return errno;
}

static void test4(void)
{
        int ret;
        int fd;

        printf("mmap test4 fd = /dev/null and MAP_PRIVATE\n");

        fd = open("/dev/null", O_RDWR);
        if (fd == -1) {
                printf("open error\n");
                return;
        }

        ret = do_mmap_test(fd, MAP_PRIVATE);

        print_result("test4", ret);

        close(fd);
}

static void test3(void)
{
        int ret;
        int fd;

        printf("mmap test3: fd = /dev/null and MAP_ANON\n");

        fd = open("/dev/null", O_RDWR);
        if (fd == -1) {
                printf("open error\n");
                return;
        }

        ret = do_mmap_test(fd, MAP_ANON);

        print_result("test3", ret);

        close(fd);
}

static void test2(void)
{
        int ret;

        printf("mmap test2: fd = -1 and MAP_PRIVATE\n");

        ret = do_mmap_test(-1, MAP_PRIVATE);

        print_result("test2", ret);

}

static void test1(void)
{
        int ret;

        printf("mmap test1: fd = -1 and MAP_ANON\n");
        ret = do_mmap_test(-1, MAP_ANON);

        print_result("test1", ret);
}

int main(int argc, char **argv)
{
        test1();
        test2();
        test3();
        test4();

        return 0;
}

これをコンパイルして実行すると、こんな感じに。

[masami@minix:/home/masami]$ ./a.out
mmap test1: fd = -1 and MAP_ANON
test test1 was succeed(errno is 0)
mmap test2: fd = -1 and MAP_PRIVATE
test test2 was succeed(errno is 0)
mmap test3: fd = /dev/null and MAP_ANON
test test3 was failed(errno is 22)
mmap test4 fd = /dev/null and MAP_PRIVATE
test test4 was failed(errno is 38)

結局、fdに-1を渡せばアノニマスmmapできるけど、fdが何かのファイルディスクリプタを指しているとmmapは失敗する。

この辺の動きをLinuxと合わせるのはおもしろそうなので、時間を見つつハックしよう(*゚▽゚)ノ

追記:
メモリの割り当てはmap_page_region()が主要な処理をになっているもよう。