int bdrv_commit(BlockDriverState *bs)

{

    BlockDriver *drv = bs->drv;

    int64_t sector, total_sectors, length, backing_length;

    int n, ro, open_flags;

    int ret = 0;

    uint8_t *buf = NULL;

    char filename[PATH_MAX];



    if (!drv)

        return -ENOMEDIUM;

    

    if (!bs->backing_hd) {

        return -ENOTSUP;

    }



    if (bdrv_in_use(bs) || bdrv_in_use(bs->backing_hd)) {

        return -EBUSY;

    }



    ro = bs->backing_hd->read_only;

    

    pstrcpy(filename, sizeof(filename), bs->backing_hd->filename);

    open_flags =  bs->backing_hd->open_flags;



    if (ro) {

        if (bdrv_reopen(bs->backing_hd, open_flags | BDRV_O_RDWR, NULL)) {

            return -EACCES;

        }

    }



    length = bdrv_getlength(bs);

    if (length < 0) {

        ret = length;

        goto ro_cleanup;

    }



    backing_length = bdrv_getlength(bs->backing_hd);

    if (backing_length < 0) {

        ret = backing_length;

        goto ro_cleanup;

    }



    





    if (length > backing_length) {

        ret = bdrv_truncate(bs->backing_hd, length);

        if (ret < 0) {

            goto ro_cleanup;

        }

    }



    total_sectors = length >> BDRV_SECTOR_BITS;

    buf = g_malloc(COMMIT_BUF_SECTORS * BDRV_SECTOR_SIZE);



    for (sector = 0; sector < total_sectors; sector += n) {

        ret = bdrv_is_allocated(bs, sector, COMMIT_BUF_SECTORS, &n);

        if (ret < 0) {

            goto ro_cleanup;

        }

        if (ret) {

            ret = bdrv_read(bs, sector, buf, n);

            if (ret < 0) {

                goto ro_cleanup;

            }



            ret = bdrv_write(bs->backing_hd, sector, buf, n);

            if (ret < 0) {

                goto ro_cleanup;

            }

        }

    }



    if (drv->bdrv_make_empty) {

        ret = drv->bdrv_make_empty(bs);

        if (ret < 0) {

            goto ro_cleanup;

        }

        bdrv_flush(bs);

    }



    







    if (bs->backing_hd) {

        bdrv_flush(bs->backing_hd);

    }



    ret = 0;

ro_cleanup:

    g_free(buf);



    if (ro) {

        

        bdrv_reopen(bs->backing_hd, open_flags & ~BDRV_O_RDWR, NULL);

    }



    return ret;

}
