存档

2012年8月 的存档

open 的同步标记

2012年8月13日 3 条评论

open 是 Linux 下打开文件的标准 API, 这个 API 同时定义了很多文件操作的参数, 不同的参数对性能影响很大. 事实上, 对同步的参数来讲(O_SYNC 系列), 默认的参数 很快, 但是会损失一些功能, 比如 cache 的存在并没有真正的把修改的内容写入文件, 如果是异常关机可能导致磁盘数据和内存没有同步, 对某些应用(如虚拟机)意味着磁盘 可能损坏.

O_SYNC

同步 I/O 的标记, 执行 write 时, 保证数据被写入硬件才返回, 也就是说调用 write 写数据的时候, write 将被阻塞, 直到所有数据(包括文件内容和文件属性) 都写入了底层硬件.

O_DSYNC

和 O_SYNC 类似, 只不过这个标记保证的只是文件的内容被写入底层硬件, 并不保证 文件属性的同步.

O_DIRECT

POSIX 并没有包含这个标志, 在 Linux 上使用的时候必须要定义 _GNU_SOURCE 这个宏. 如果使用这个标志, 数据的传输将不会通过内核空间, 而是使用 DMA 直接在用户空间 到存储设备之间传送, 不保证数据是否同步. 所以 O_DIRECT 常和 O_SYNC 一起 保证数据的同步和效率.

测试

我写了一个简单的测试程序来测试以上参数对数据读写的影响.

测试结果
Flags Used Time
Default 3ms
O_SYNC 90000ms
O_DSYNC 30000ms
O_DIRECT 1ms
O_SYNC and O_DIRECT 1ms

测试代码:

#define _GNU_SOURCE
 
#include <sys/types.h>
#include <sys/stat.h>
#include 
#include 
#include 
#include 
 
/* #define USE_SYNC 1 */
/* #define USE_DSYNC 1 */
/* #define USE_DIRECT 1 */
 
void test()
{
    int fd;
    int i;
    int offset = 0;
    unsigned char buf[512] = "1234567890";
    int flags = 0;
 
#ifdef USE_DIRECT
    void *align_buf = NULL;
    if (posix_memalign(&align_buf, 512, sizeof(buf)) != 0) {
        perror("memalign failed");
        return;
    }
#endif
 
    flags = O_WRONLY | O_CREAT | O_TRUNC;
#ifdef USE_SYNC
    printf("USE O_SYNC flag\n");
    flags |= O_SYNC;
#endif
#ifdef USE_DSYNC
    printf("USE O_DSYNC flag\n");
    flags |= O_DSYNC;
#endif
#ifdef USE_DIRECT
    printf("USE O_DIRECT flag\n");
    flags |= O_DIRECT;
#endif
    fd = open("/tmp/test.bin", flags, 0644);
 
    if (fd == -1) {
        perror("Create file failed");
        return;
    }
    if (ftruncate(fd, 10 * 1024 * 1024)) {
        goto cleanup;
    }
 
    for (i = 0; i < 2048; ++i) {
#ifdef USE_DIRECT
        int len = pwrite(fd, align_buf, sizeof(buf), offset);
#else
        int len = pwrite(fd, buf, sizeof(buf), offset);
#endif
    if (len < 0) {
            perror("failed to write");
            break;
    } else if (len == 0) {
            break;
            /* ? */
        }
        offset += len;
    }
 
cleanup:
    if (fd != -1) {
        close(fd);
    }
#ifdef USE_DIRECT
    if (align_buf) {
        free(align_buf);
    }
#endif
}
 
int main(int argc, char *argv[])
{
    test();
    return 0;
}
分类: linux 标签:

Nested KVM

2012年8月11日 没有评论

最近同事抱怨开发的机器不够用, 由于是研发 KVM 相关的程序, 所以需要有带有硬件 虚拟化支持的机器. 其实公司服务器很多都是闲置的, 所以只要 Guest 能支持 KVM, 问题就迎刃而解了. 简单的对这个问题做了一下研究.

概念

Nested KVM 指的是在 一个运行的 KVM 虚拟机里面在运行 KVM 虚拟机.

现在 Nested KVM 已经相对稳定了(以前 Nest KVM 甚至不支持 Intel 的 CPU).

实现

配置 KVM 模块

首先需要加载 KVM 模块, 这个地球人都知道, 我就不多说了, 不知道的翻我以前的 BLOG

Intel 的 Nested KVM 配置

检查是否开启了 Nested KVM,

 $ cat /sys/module/kvm_intel/parameters/nested Y 

如果结果是 Y, 那么说明加载 KVM 的时候已经开启了 Nested KVM, 否则使用以 下指令重载 KVM 模块

 $ sudo modprobe -r kvm-intel $ sudo modprobe kvm-intel nested=1 

AMD 的 Nested KVM 配置

AMD 的和 KVM 的类似.

检查是否开启了 Nested KVM,

 $ cat /sys/module/kvm_amd/parameters/nested 1 

如果结果是 1, 那么说明加载 KVM 的时候已经开启了 Nested KVM, 否则使用以 下指令重载 KVM 模块

 $ sudo modprobe -r kvm-amd $ sudo modprobe kvm-amd nested=1 

启动虚拟机

首先说明一点, Nested KVM 在 QEMU 里面经过了一些变化, 见此.

主要是之前 QEMU 有一个选项 -enable-nesting 用来开启这个功能的, 但是有一些 developper 谈到在那个时候 Intel 不支持该功能, 所以建议把这个选项去掉, 如果 是 AMD 的 CPU, 默认开启这个功能.

所以有以下的两种情况:

旧版本的 QEMU/KVM

旧版本的 QEMU/KVM 不支持 Intel 的 CPU, 所以如果是 Intel 的 CPU, 就不用尝试了.

 $ qemu-system-x86_64 enable-kvm -enable-nesting -cpu host -m 512 debian.raw 

请注意 -enable-nesting 参数, 没有也可能开启此功能, 但是不保证成功, 我在 16 核的 AMD 上测试的结果是没有 -enable-nesting 参数是没有此功能的.

PS, 我在 CentOS-6.3(内核版本 2.6.32-220.el6.x86_64) 上测试时, “AMD Opteron(tm) Processor 6128” 启动虚拟机启动失败, 换成 “amd opteron” 就没有问题.

新版的 QEMU/KVM

 $ qemu-system-x86_64 enable-kvm -cpu host -m 512 debian.raw 

新版的 nested KVM 完全不需要 QEMU 作任何修改, 只需要指定 cpu 参数就行了, 这里我选择模拟和 host 一样的 CPU.

分类: kvm, QEMU 标签: ,