searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

qemu-img的介绍

2024-06-21 09:38:22
13
0

emu-img 是 QEMU 虚拟机管理工具套件中的一个工具,用于创建、转换、修改和管理磁盘映像文件。

常用命令

  1. 创建映像
    qemu-img create 命令创建一个新的磁盘映像文件。
    qemu-img create -f qcow2 mydisk.img 10G
  2. 查看磁盘映像信息
    使用 qemu-img info 命令查看磁盘映像的详细信息。
    qemu-img info mydisk.img
  3. 转换磁盘映像格式
    qemu-img convert 命令将磁盘映像从一个格式转换为另一个格式。
    qemu-img convert -f raw -O qcow2 myrawdisk.img myqcow2disk.img
  4. 调整磁盘映像大小
    qemu-img resize 命令调整磁盘映像的大小。注意,这只会更改映像的元数据,不会实际写入新数据。
    qemu-img resize mydisk.img +2G

实际使用

目前对resize进行验证,首先进入虚机查看分区信息:

Filesystem      Size  Used Avail Use% Mounted on
/dev/root       3.0G  2.4G  627M  80% /
tmpfs           3.8G  460K  3.8G   1% /dev
tmpfs           3.8G  4.0K  3.8G   1% /mnt
/dev/block/vde1 0.9G  321M  671M  33% /vendor
/dev/block/vdc   63G   61M   62G   1% /data

在虚机外部,执行resize操作:

bash-4.2# qemu-img resize userdata-qemu.img.qcow2 +5G
Image resized.

最后查看实际空间信息,可以看到data分区已经增加。

/dev/root       3.0G  2.4G  627M  80% /
tmpfs           3.8G  456K  3.8G   1% /dev
tmpfs           3.8G  4.0K  3.8G   1% /mnt
/dev/block/vde1 0.9G  321M  671M  33% /vendor
/dev/block/vdc   68G  484M   67G   1% /data

代码相关

create、info、convert和reszie分别对应qemu-img.c中的img_createimg_infoimg_convertimg_resize
例如示例中的resize实现如下:

static int img_resize(int argc, char **argv)
{
    Error *err = NULL;
    int c, ret, relative;
    const char *filename, *fmt, *size;
    int64_t n, total_size, current_size;
    bool quiet = false;
    BlockBackend *blk = NULL;
    PreallocMode prealloc = PREALLOC_MODE_OFF;
    QemuOpts *param;

    static QemuOptsList resize_options = {
        .name = "resize_options",
        .head = QTAILQ_HEAD_INITIALIZER(resize_options.head),
        .desc = {
            {
                .name = BLOCK_OPT_SIZE,
                .type = QEMU_OPT_SIZE,
                .help = "Virtual disk size"
            }, {
                /* end of list */
            }
        },
    };
    bool image_opts = false;
    bool shrink = false;

    /* Remove size from argv manually so that negative numbers are not treated
     * as options by getopt. */
    if (argc < 3) {
        error_exit("Not enough arguments");
        return 1;
    }

    size = argv[--argc];

    /* Parse getopt arguments */
    fmt = NULL;
    for(;;) {
        static const struct option long_options[] = {
            {"help", no_argument, 0, 'h'},
            {"object", required_argument, 0, OPTION_OBJECT},
            {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
            {"preallocation", required_argument, 0, OPTION_PREALLOCATION},
            {"shrink", no_argument, 0, OPTION_SHRINK},
            {0, 0, 0, 0}
        };
        c = getopt_long(argc, argv, ":f:hq",
                        long_options, NULL);
        if (c == -1) {
            break;
        }
        switch(c) {
        case ':':
            missing_argument(argv[optind - 1]);
            break;
        case '?':
            unrecognized_option(argv[optind - 1]);
            break;
        case 'h':
            help();
            break;
        case 'f':
            fmt = optarg;
            break;
        case 'q':
            quiet = true;
            break;
        case OPTION_OBJECT:
            user_creatable_process_cmdline(optarg);
            break;
        case OPTION_IMAGE_OPTS:
            image_opts = true;
            break;
        case OPTION_PREALLOCATION:
            prealloc = qapi_enum_parse(&PreallocMode_lookup, optarg,
                                       PREALLOC_MODE__MAX, NULL);
            if (prealloc == PREALLOC_MODE__MAX) {
                error_report("Invalid preallocation mode '%s'", optarg);
                return 1;
            }
            break;
        case OPTION_SHRINK:
            shrink = true;
            break;
        }
    }
    if (optind != argc - 1) {
        error_exit("Expecting image file name and size");
    }
    filename = argv[optind++];

    /* Choose grow, shrink, or absolute resize mode */
    switch (size[0]) {
    case '+':
        relative = 1;
        size++;
        break;
    case '-':
        relative = -1;
        size++;
        break;
    default:
        relative = 0;
        break;
    }

    /* Parse size */
    param = qemu_opts_create(&resize_options, NULL, 0, &error_abort);
    if (!qemu_opt_set(param, BLOCK_OPT_SIZE, size, &err)) {
        error_report_err(err);
        ret = -1;
        qemu_opts_del(param);
        goto out;
    }
    n = qemu_opt_get_size(param, BLOCK_OPT_SIZE, 0);
    qemu_opts_del(param);

    blk = img_open(image_opts, filename, fmt,
                   BDRV_O_RDWR | BDRV_O_RESIZE, false, quiet,
                   false);
    if (!blk) {
        ret = -1;
        goto out;
    }

    current_size = blk_getlength(blk);
    if (current_size < 0) {
        error_report("Failed to inquire current image length: %s",
                     strerror(-current_size));
        ret = -1;
        goto out;
    }

    if (relative) {
        total_size = current_size + n * relative;
    } else {
        total_size = n;
    }
    if (total_size <= 0) {
        error_report("New image size must be positive");
        ret = -1;
        goto out;
    }

    if (total_size <= current_size && prealloc != PREALLOC_MODE_OFF) {
        error_report("Preallocation can only be used for growing images");
        ret = -1;
        goto out;
    }

    if (total_size < current_size && !shrink) {
        error_report("Use the --shrink option to perform a shrink operation.");
        warn_report("Shrinking an image will delete all data beyond the "
                    "shrunken image's end. Before performing such an "
                    "operation, make sure there is no important data there.");
        ret = -1;
        goto out;
    }

    /*
     * The user expects the image to have the desired size after
     * resizing, so pass @exact=true.  It is of no use to report
     * success when the image has not actually been resized.
     */
    ret = blk_truncate(blk, total_size, true, prealloc, 0, &err);
    if (!ret) {
        qprintf(quiet, "Image resized.\n");
    } else {
        error_report_err(err);
    }
out:
    blk_unref(blk);
    if (ret) {
        return 1;
    }
    return 0;
}

这里核心调用的就是blk_truncate(blk, total_size, true, prealloc, 0, &err)函数。

0条评论
0 / 1000
张****龙
17文章数
0粉丝数
张****龙
17 文章 | 0 粉丝