QEMU/KVM中磁盘cache关闭(cache=off/none)

前阵子有同事问到KVM中关于磁盘的cache的问题,我一直没有深究,今天好好看了下qemu-kvm的代码。在QEMU/KVM命令行的drive参数中,加上”cache=off”或”cache=none”都是将宿主机中对客户机镜像的读写cache关闭的,因为它open那个image文件时就是用”O_DIRECT”方式打开的,下面进行分析如下。
本次分析基于qemu-kvm.git代码,使用其中的”qemu-kvm-1.1.1″这个tag。
首先,vl.c解析QEMU命令行参数,可以看到对“drive”的解析如下:

if (qemu_opts_foreach(qemu_find_opts("drive"), drive_init_func, &machine->use_scsi, 1) != 0)
        exit(1);

static int drive_init_func(QemuOpts *opts, void *opaque)
{
    int *use_scsi = opaque;

    return drive_init(opts, *use_scsi) == NULL;
}

然后,drive_init函数是在blockdev.c文件中定义的,如下:

DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
{
/*..................*/
    if ((buf = qemu_opt_get(opts, "cache")) != NULL) {
        if (bdrv_parse_cache_flags(buf, &bdrv_flags) != 0) {
            error_report("invalid cache option");
            return NULL;
        }
    }
/*..................*/
}


而对block devicecache标志的解析在block.c文件的“bdrv_parse_cache_flags”函数,如下:

/**
 * Set open flags for a given cache mode
 *
 * Return 0 on success, -1 if the cache mode was invalid.
 */
int bdrv_parse_cache_flags(const char *mode, int *flags)
{
    *flags &= ~BDRV_O_CACHE_MASK;

    if (!strcmp(mode, "off") || !strcmp(mode, "none")) {
        *flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB;
    } else if (!strcmp(mode, "directsync")) {
        *flags |= BDRV_O_NOCACHE;
    } else if (!strcmp(mode, "writeback")) {
        *flags |= BDRV_O_CACHE_WB;
    } else if (!strcmp(mode, "unsafe")) {
        *flags |= BDRV_O_CACHE_WB;
        *flags |= BDRV_O_NO_FLUSH;
    } else if (!strcmp(mode, "writethrough")) {
        /* this is the default */
    } else {
        return -1;
    }

    return 0;
}

可见,cache=off/none,将被标志为“BDRV_O_NOCACHE”和“BDRV_O_CACHE_WB”,而将这些标志转换为open系统调用的flag在”block/raw-posix.c”文件中,如下:

    /* Use O_DSYNC for write-through caching, no flags for write-back caching,
     * and O_DIRECT for no caching. */
    if ((bdrv_flags & BDRV_O_NOCACHE))
        s->open_flags |= O_DIRECT;
    if (!(bdrv_flags & BDRV_O_CACHE_WB))
        s->open_flags |= O_DSYNC;

可见,open syscall的falg被置为”O_DIRECT”了,而最后正式调用open去打开文件的代码在”osdep.c”中,如下:

    s->fd = -1;
    fd = qemu_open(filename, s->open_flags, 0644);

    #ifdef O_CLOEXEC
    ret = open(name, flags | O_CLOEXEC, mode);
#else
    ret = open(name, flags, mode);
    if (ret >= 0) {
        qemu_set_cloexec(ret);
    }
#endif

对于open系统调用,可以“man 2 open”来了解;对于前面的strcmp函数,可以“man 3 strcmp”来查看。

master

Stay hungry, stay foolish.

One Comment

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

*