static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
                         Error **errp)
{
    BDRVQEDState *s = bs->opaque;
    QEDHeader le_header;
    int64_t file_size;
    int ret;
    s->bs = bs;
    QSIMPLEQ_INIT(&s->allocating_write_reqs);
    ret = bdrv_pread(bs->file, 0, &le_header, sizeof(le_header));
    if (ret < 0) {
        return ret;
    qed_header_le_to_cpu(&le_header, &s->header);
    if (s->header.magic != QED_MAGIC) {
        error_setg(errp, "Image not in QED format");
    if (s->header.features & ~QED_FEATURE_MASK) {
        /* image uses unsupported feature bits */
        char buf[64];
        snprintf(buf, sizeof(buf), "%" PRIx64,
            s->header.features & ~QED_FEATURE_MASK);
        error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
            bdrv_get_device_name(bs), "QED", buf);
        return -ENOTSUP;
    if (!qed_is_cluster_size_valid(s->header.cluster_size)) {
    /* Round down file size to the last cluster */
    file_size = bdrv_getlength(bs->file);
    if (file_size < 0) {
        return file_size;
    s->file_size = qed_start_of_cluster(s, file_size);
    if (!qed_is_table_size_valid(s->header.table_size)) {
    if (!qed_is_image_size_valid(s->header.image_size,
                                 s->header.cluster_size,
                                 s->header.table_size)) {
    if (!qed_check_table_offset(s, s->header.l1_table_offset)) {
    s->table_nelems = (s->header.cluster_size * s->header.table_size) /
                      sizeof(uint64_t);
    s->l2_shift = ffs(s->header.cluster_size) - 1;
    s->l2_mask = s->table_nelems - 1;
    s->l1_shift = s->l2_shift + ffs(s->table_nelems) - 1;
    if ((s->header.features & QED_F_BACKING_FILE)) {
        if ((uint64_t)s->header.backing_filename_offset +
            s->header.backing_filename_size >
            s->header.cluster_size * s->header.header_size) {
        ret = qed_read_string(bs->file, s->header.backing_filename_offset,
                              s->header.backing_filename_size, bs->backing_file,
                              sizeof(bs->backing_file));
        if (ret < 0) {
            return ret;
        if (s->header.features & QED_F_BACKING_FORMAT_NO_PROBE) {
            pstrcpy(bs->backing_format, sizeof(bs->backing_format), "raw");
    /* Reset unknown autoclear feature bits.  This is a backwards
     * compatibility mechanism that allows images to be opened by older
     * programs, which "knock out" unknown feature bits.  When an image is
     * opened by a newer program again it can detect that the autoclear
     * feature is no longer valid.
     */
    if ((s->header.autoclear_features & ~QED_AUTOCLEAR_FEATURE_MASK) != 0 &&
        !bdrv_is_read_only(bs->file) && !(flags & BDRV_O_INCOMING)) {
        s->header.autoclear_features &= QED_AUTOCLEAR_FEATURE_MASK;
        ret = qed_write_header_sync(s);
        if (ret) {
            return ret;
        /* From here on only known autoclear feature bits are valid */
        bdrv_flush(bs->file);
    s->l1_table = qed_alloc_table(s);
    qed_init_l2_cache(&s->l2_cache);
    ret = qed_read_l1_table_sync(s);
    if (ret) {
        goto out;
    /* If image was not closed cleanly, check consistency */
    if (!(flags & BDRV_O_CHECK) && (s->header.features & QED_F_NEED_CHECK)) {
        /* Read-only images cannot be fixed.  There is no risk of corruption
         * since write operations are not possible.  Therefore, allow
         * potentially inconsistent images to be opened read-only.  This can
         * aid data recovery from an otherwise inconsistent image.
         */
        if (!bdrv_is_read_only(bs->file) &&
            !(flags & BDRV_O_INCOMING)) {
            BdrvCheckResult result = {0};
            ret = qed_check(s, &result, true);
            if (ret) {
                goto out;
    bdrv_qed_attach_aio_context(bs, bdrv_get_aio_context(bs));
out:
    if (ret) {
        qed_free_l2_cache(&s->l2_cache);
        qemu_vfree(s->l1_table);
    return ret;
static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
                         Error **errp)
{
    BDRVQEDState *s = bs->opaque;
    QEDHeader le_header;
    int64_t file_size;
    int ret;
    s->bs = bs;
    QSIMPLEQ_INIT(&s->allocating_write_reqs);
    ret = bdrv_pread(bs->file, 0, &le_header, sizeof(le_header));
    if (ret < 0) {
        return ret;
    qed_header_le_to_cpu(&le_header, &s->header);
    if (s->header.magic != QED_MAGIC) {
        error_setg(errp, "Image not in QED format");
    if (s->header.features & ~QED_FEATURE_MASK) {
        
        char buf[64];
        snprintf(buf, sizeof(buf), "%" PRIx64,
            s->header.features & ~QED_FEATURE_MASK);
        error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
            bdrv_get_device_name(bs), "QED", buf);
        return -ENOTSUP;
    if (!qed_is_cluster_size_valid(s->header.cluster_size)) {
    
    file_size = bdrv_getlength(bs->file);
    if (file_size < 0) {
        return file_size;
    s->file_size = qed_start_of_cluster(s, file_size);
    if (!qed_is_table_size_valid(s->header.table_size)) {
    if (!qed_is_image_size_valid(s->header.image_size,
                                 s->header.cluster_size,
                                 s->header.table_size)) {
    if (!qed_check_table_offset(s, s->header.l1_table_offset)) {
    s->table_nelems = (s->header.cluster_size * s->header.table_size) /
                      sizeof(uint64_t);
    s->l2_shift = ffs(s->header.cluster_size) - 1;
    s->l2_mask = s->table_nelems - 1;
    s->l1_shift = s->l2_shift + ffs(s->table_nelems) - 1;
    if ((s->header.features & QED_F_BACKING_FILE)) {
        if ((uint64_t)s->header.backing_filename_offset +
            s->header.backing_filename_size >
            s->header.cluster_size * s->header.header_size) {
        ret = qed_read_string(bs->file, s->header.backing_filename_offset,
                              s->header.backing_filename_size, bs->backing_file,
                              sizeof(bs->backing_file));
        if (ret < 0) {
            return ret;
        if (s->header.features & QED_F_BACKING_FORMAT_NO_PROBE) {
            pstrcpy(bs->backing_format, sizeof(bs->backing_format), "raw");
    





    if ((s->header.autoclear_features & ~QED_AUTOCLEAR_FEATURE_MASK) != 0 &&
        !bdrv_is_read_only(bs->file) && !(flags & BDRV_O_INCOMING)) {
        s->header.autoclear_features &= QED_AUTOCLEAR_FEATURE_MASK;
        ret = qed_write_header_sync(s);
        if (ret) {
            return ret;
        
        bdrv_flush(bs->file);
    s->l1_table = qed_alloc_table(s);
    qed_init_l2_cache(&s->l2_cache);
    ret = qed_read_l1_table_sync(s);
    if (ret) {
        goto out;
    
    if (!(flags & BDRV_O_CHECK) && (s->header.features & QED_F_NEED_CHECK)) {
        




        if (!bdrv_is_read_only(bs->file) &&
            !(flags & BDRV_O_INCOMING)) {
            BdrvCheckResult result = {0};
            ret = qed_check(s, &result, true);
            if (ret) {
                goto out;
    bdrv_qed_attach_aio_context(bs, bdrv_get_aio_context(bs));
out:
    if (ret) {
        qed_free_l2_cache(&s->l2_cache);
        qemu_vfree(s->l1_table);
    return ret;
static int FUNC_0(BlockDriverState *VAR_0, QDict *VAR_1, int VAR_2,
                         Error **VAR_3)
{
    BDRVQEDState *s = VAR_0->opaque;
    QEDHeader le_header;
    int64_t file_size;
    int VAR_4;
    s->VAR_0 = VAR_0;
    QSIMPLEQ_INIT(&s->allocating_write_reqs);
    VAR_4 = bdrv_pread(VAR_0->file, 0, &le_header, sizeof(le_header));
    if (VAR_4 < 0) {
        return VAR_4;
    qed_header_le_to_cpu(&le_header, &s->header);
    if (s->header.magic != QED_MAGIC) {
        error_setg(VAR_3, "Image not in QED format");
    if (s->header.features & ~QED_FEATURE_MASK) {
        
        char VAR_5[64];
        snprintf(VAR_5, sizeof(VAR_5), "%" PRIx64,
            s->header.features & ~QED_FEATURE_MASK);
        error_set(VAR_3, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
            bdrv_get_device_name(VAR_0), "QED", VAR_5);
        return -ENOTSUP;
    if (!qed_is_cluster_size_valid(s->header.cluster_size)) {
    
    file_size = bdrv_getlength(VAR_0->file);
    if (file_size < 0) {
        return file_size;
    s->file_size = qed_start_of_cluster(s, file_size);
    if (!qed_is_table_size_valid(s->header.table_size)) {
    if (!qed_is_image_size_valid(s->header.image_size,
                                 s->header.cluster_size,
                                 s->header.table_size)) {
    if (!qed_check_table_offset(s, s->header.l1_table_offset)) {
    s->table_nelems = (s->header.cluster_size * s->header.table_size) /
                      sizeof(uint64_t);
    s->l2_shift = ffs(s->header.cluster_size) - 1;
    s->l2_mask = s->table_nelems - 1;
    s->l1_shift = s->l2_shift + ffs(s->table_nelems) - 1;
    if ((s->header.features & QED_F_BACKING_FILE)) {
        if ((uint64_t)s->header.backing_filename_offset +
            s->header.backing_filename_size >
            s->header.cluster_size * s->header.header_size) {
        VAR_4 = qed_read_string(VAR_0->file, s->header.backing_filename_offset,
                              s->header.backing_filename_size, VAR_0->backing_file,
                              sizeof(VAR_0->backing_file));
        if (VAR_4 < 0) {
            return VAR_4;
        if (s->header.features & QED_F_BACKING_FORMAT_NO_PROBE) {
            pstrcpy(VAR_0->backing_format, sizeof(VAR_0->backing_format), "raw");
    





    if ((s->header.autoclear_features & ~QED_AUTOCLEAR_FEATURE_MASK) != 0 &&
        !bdrv_is_read_only(VAR_0->file) && !(VAR_2 & BDRV_O_INCOMING)) {
        s->header.autoclear_features &= QED_AUTOCLEAR_FEATURE_MASK;
        VAR_4 = qed_write_header_sync(s);
        if (VAR_4) {
            return VAR_4;
        
        bdrv_flush(VAR_0->file);
    s->l1_table = qed_alloc_table(s);
    qed_init_l2_cache(&s->l2_cache);
    VAR_4 = qed_read_l1_table_sync(s);
    if (VAR_4) {
        goto out;
    
    if (!(VAR_2 & BDRV_O_CHECK) && (s->header.features & QED_F_NEED_CHECK)) {
        




        if (!bdrv_is_read_only(VAR_0->file) &&
            !(VAR_2 & BDRV_O_INCOMING)) {
            BdrvCheckResult result = {0};
            VAR_4 = qed_check(s, &result, true);
            if (VAR_4) {
                goto out;
    bdrv_qed_attach_aio_context(VAR_0, bdrv_get_aio_context(VAR_0));
out:
    if (VAR_4) {
        qed_free_l2_cache(&s->l2_cache);
        qemu_vfree(s->l1_table);
    return VAR_4;
static int FUNC_0(BlockDriverState *VAR_0, QDict *VAR_1, int VAR_2,
Error **VAR_3)
{ BDRVQEDState *s = VAR_0->opaque; QEDHeader le_header; int64_t file_size; int VAR_4; s->VAR_0 = VAR_0; QSIMPLEQ_INIT(&s->allocating_write_reqs); VAR_4 = bdrv_pread(VAR_0->file, 0, &le_header, sizeof(le_header)); if (VAR_4 < 0) { return VAR_4; qed_header_le_to_cpu(&le_header, &s->header); if (s->header.magic != QED_MAGIC) { error_setg(VAR_3, "Image not in QED format"); if (s->header.features & ~QED_FEATURE_MASK) { char VAR_5[64]; snprintf(VAR_5, sizeof(VAR_5), "%" PRIx64,
s->header.features & ~QED_FEATURE_MASK); error_set(VAR_3, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
bdrv_get_device_name(VAR_0), "QED", VAR_5); return -ENOTSUP; if (!qed_is_cluster_size_valid(s->header.cluster_size)) { file_size = bdrv_getlength(VAR_0->file); if (file_size < 0) { return file_size; s->file_size = qed_start_of_cluster(s, file_size); if (!qed_is_table_size_valid(s->header.table_size)) { if (!qed_is_image_size_valid(s->header.image_size,
s->header.cluster_size,
s->header.table_size)) { if (!qed_check_table_offset(s, s->header.l1_table_offset)) { s->table_nelems = (s->header.cluster_size * s->header.table_size) /
sizeof(uint64_t); s->l2_shift = ffs(s->header.cluster_size) - 1; s->l2_mask = s->table_nelems - 1; s->l1_shift = s->l2_shift + ffs(s->table_nelems) - 1; if ((s->header.features & QED_F_BACKING_FILE)) { if ((uint64_t)s->header.backing_filename_offset +
s->header.backing_filename_size >
s->header.cluster_size * s->header.header_size) { VAR_4 = qed_read_string(VAR_0->file, s->header.backing_filename_offset,
s->header.backing_filename_size, VAR_0->backing_file,
sizeof(VAR_0->backing_file)); if (VAR_4 < 0) { return VAR_4; if (s->header.features & QED_F_BACKING_FORMAT_NO_PROBE) { pstrcpy(VAR_0->backing_format, sizeof(VAR_0->backing_format), "raw"); if ((s->header.autoclear_features & ~QED_AUTOCLEAR_FEATURE_MASK) != 0 &&
!bdrv_is_read_only(VAR_0->file) && !(VAR_2 & BDRV_O_INCOMING)) { s->header.autoclear_features &= QED_AUTOCLEAR_FEATURE_MASK; VAR_4 = qed_write_header_sync(s); if (VAR_4) { return VAR_4; bdrv_flush(VAR_0->file); s->l1_table = qed_alloc_table(s); qed_init_l2_cache(&s->l2_cache); VAR_4 = qed_read_l1_table_sync(s); if (VAR_4) { goto out; if (!(VAR_2 & BDRV_O_CHECK) && (s->header.features & QED_F_NEED_CHECK)) { if (!bdrv_is_read_only(VAR_0->file) &&
!(VAR_2 & BDRV_O_INCOMING)) { BdrvCheckResult result = {0}; VAR_4 = qed_check(s, &result, true); if (VAR_4) { goto out; bdrv_qed_attach_aio_context(VAR_0, bdrv_get_aio_context(VAR_0)); out:
if (VAR_4) { qed_free_l2_cache(&s->l2_cache); qemu_vfree(s->l1_table); return VAR_4;