예제 #1
0
파일: testlibrbd.c 프로젝트: tcloud/ceph
int main(int argc, const char **argv) 
{
  rados_t cluster;
  rados_ioctx_t io_ctx;
  rbd_image_t image;

  srand(time(0));

  assert(rados_create(&cluster, NULL) == 0);
  assert(rados_conf_parse_argv(cluster, argc, argv) == 0);
  assert(rados_conf_read_file(cluster, NULL) == 0);
  assert(rados_connect(cluster) == 0);

  if (rados_pool_lookup(cluster, TEST_POOL) != -ENOENT) {
    int r = rados_pool_delete(cluster, TEST_POOL);
    printf("rados_pool_delete returned %d\n", r);
  }
  int r = rados_pool_create(cluster, TEST_POOL);
  printf("rados_pool_create returned %d\n", r);

  assert(rados_ioctx_create(cluster, TEST_POOL, &io_ctx) == 0);
  test_ls(io_ctx, 0);

  test_create_and_stat(io_ctx, TEST_IMAGE, MB_BYTES(1));
  assert(rbd_open(io_ctx, TEST_IMAGE, &image, NULL) == 0);

  test_ls(io_ctx, 1, TEST_IMAGE);
  test_ls_snaps(image, 0);

  test_create_snap(image, TEST_SNAP);
  test_ls_snaps(image, 1, TEST_SNAP, MB_BYTES(1));
  test_resize_and_stat(image, MB_BYTES(2));
  test_io(io_ctx, image);

  test_create_snap(image, TEST_SNAP "1");
  test_ls_snaps(image, 2, TEST_SNAP, MB_BYTES(1), TEST_SNAP "1", MB_BYTES(2));

  test_delete_snap(image, TEST_SNAP);
  test_ls_snaps(image, 1, TEST_SNAP "1", MB_BYTES(2));

  test_delete_snap(image, TEST_SNAP "1");
  test_ls_snaps(image, 0);

  test_io_to_snapshot(io_ctx, image, MB_BYTES(2));
  assert(rbd_close(image) == 0);

  test_create_and_stat(io_ctx, TEST_IMAGE "1", MB_BYTES(2));
  test_ls(io_ctx, 2, TEST_IMAGE, TEST_IMAGE "1");

  test_delete(io_ctx, TEST_IMAGE);
  test_ls(io_ctx, 1, TEST_IMAGE "1");

  test_delete(io_ctx, TEST_IMAGE "1");
  test_ls(io_ctx, 0);

  rados_ioctx_destroy(io_ctx);
  rados_shutdown(cluster);

  return 0;
}
예제 #2
0
파일: rbd.c 프로젝트: coypoop/riscv-qemu
static void qemu_rbd_close(BlockDriverState *bs)
{
    BDRVRBDState *s = bs->opaque;

    rbd_close(s->image);
    rados_ioctx_destroy(s->io_ctx);
    g_free(s->snap);
    rados_shutdown(s->cluster);
}
예제 #3
0
파일: fsx.c 프로젝트: athanatos/ceph
void
do_clone()
{
	char filename[1024];
	char imagename[1024];
	char lastimagename[1024];
	int ret, fd;
	int order = 0, stripe_unit = 0, stripe_count = 0;

	if (randomize_striping) {
		order = 18 + rand() % 8;
		stripe_unit = 1ull << (order - 1 - (rand() % 8));
		stripe_count = 2 + rand() % 14;
	}

	log4(OP_CLONE, 0, 0, 0);
	++num_clones;
	prt("%lu clone\t%d order %d su %d sc %d\n", testcalls, num_clones, order, stripe_unit, stripe_count);

	clone_filename(filename, sizeof(filename), num_clones);
	if ((fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) {
		simple_err("do_clone: open", -errno);
		exit(162);
	}
	save_buffer(good_buf, file_size, fd);
	if ((ret = close(fd)) < 0) {
		simple_err("do_clone: close", -errno);
		exit(163);
	}

	if ((ret = rbd_snap_create(image, "snap")) < 0) {
		simple_err("do_clone: rbd create snap", ret);
		exit(164);
	}

	if ((ret = rbd_snap_protect(image, "snap")) < 0) {
		simple_err("do_clone: rbd protect snap", ret);
		exit(164);
	}

	clone_imagename(imagename, sizeof(imagename), num_clones);
	clone_imagename(lastimagename, sizeof(lastimagename),
			num_clones - 1);

	ret = rbd_clone2(ioctx, lastimagename, "snap", ioctx, imagename,
			 RBD_FEATURES_ALL, &order, stripe_unit, stripe_count);
	if (ret < 0) {
		simple_err("do_clone: rbd clone", ret);
		exit(165);
	}
	rbd_close(image);
	if ((ret = rbd_open(ioctx, imagename, &image, NULL)) < 0) {
		simple_err("do_clone: rbd open", ret);
		exit(166);
	}
}
예제 #4
0
파일: bs_rbd.c 프로젝트: chitr/tgt
static void bs_rbd_close(struct scsi_lu *lu)
{
	struct active_rbd *rbd = RBDP(lu->fd);

	if (rbd->rbd_image) {
		rbd_close(rbd->rbd_image);
		rados_ioctx_destroy(rbd->ioctx);
		rbd->rbd_image = rbd->ioctx = NULL;
	}
}
예제 #5
0
파일: testlibrbd.c 프로젝트: tcloud/ceph
void test_create_and_stat(rados_ioctx_t io_ctx, const char *name, size_t size)
{
  rbd_image_info_t info;
  rbd_image_t image;
  int order = 0;
  assert(rbd_create(io_ctx, name, size, &order) == 0);
  assert(rbd_open(io_ctx, name, &image, NULL) == 0);
  assert(rbd_stat(image, &info, sizeof(info)) == 0);
  printf("image has size %llu and order %d\n", (unsigned long long) info.size, info.order);
  assert(info.size == size);
  assert(info.order == order);
  assert(rbd_close(image) == 0);
}
예제 #6
0
파일: rbd-fuse.c 프로젝트: hufman/ceph
int
rbdfs_unlink(const char *path)
{
    int fd = find_openrbd(path+1);
    if (fd != -1) {
        struct rbd_openimage *rbd = &opentbl[fd];
        rbd_close(rbd->image);
        rbd->image = 0;
        free(rbd->image_name);
        rbd->rbd_stat.valid = 0;
    }
    return rbd_remove(ioctx, path+1);
}
예제 #7
0
static void qemu_rbd_close(BlockDriverState *bs)
{
    BDRVRBDState *s = bs->opaque;

    close(s->fds[0]);
    close(s->fds[1]);
    qemu_aio_set_fd_handler(s->fds[RBD_FD_READ], NULL, NULL, NULL, NULL);

    rbd_close(s->image);
    rados_ioctx_destroy(s->io_ctx);
    g_free(s->snap);
    rados_shutdown(s->cluster);
}
예제 #8
0
파일: fsx.c 프로젝트: athanatos/ceph
void
check_clones()
{
	char filename[1024];
	char imagename[1024];
	int ret, fd;
	rbd_image_t cur_image;
	struct stat file_info;
	while (num_clones > 0) {
		prt("checking clone #%d\n", num_clones);
		--num_clones;

		clone_imagename(imagename, sizeof(imagename), num_clones);
		if ((ret = rbd_open(ioctx, imagename, &cur_image, NULL)) < 0) {
			simple_err("check_clones: rbd open", ret);
			exit(167);
		}

		clone_filename(filename, sizeof(filename), num_clones + 1);
		if ((fd = open(filename, O_RDONLY)) < 0) {
			simple_err("check_clones: open", -errno);
			exit(168);
		}

		prt("checking image %s against file %s\n", imagename, filename);
		if ((ret = fstat(fd, &file_info)) < 0) {
			simple_err("check_clones: fstat", -errno);
			exit(169);
		}

		if ((ret = pread(fd, good_buf, file_info.st_size, 0)) < 0) {
			simple_err("check_clones: pread", -errno);
			exit(170);
		}

		if ((ret = rbd_read(cur_image, 0, file_info.st_size, temp_buf)) < 0) {
			simple_err("check_clones: rbd_read", ret);
			exit(171);
		}
		close(fd);
		check_buffers(0, file_info.st_size);

		unlink(filename);
		/* remove the snapshot if it exists, ignore
		   the error from the last clone. */
		rbd_snap_unprotect(cur_image, "snap");
		rbd_snap_remove(cur_image, "snap");
		rbd_close(cur_image);
		rbd_remove(ioctx, imagename);
	}
}
예제 #9
0
static int volStorageBackendRBDRefreshVolInfo(virStorageVolDefPtr vol,
        virStoragePoolObjPtr pool,
        virStorageBackendRBDStatePtr ptr)
{
    int ret = -1;
    rbd_image_t image;
    if (rbd_open(ptr.ioctx, vol->name, &image, NULL) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("failed to open the RBD image '%s'"),
                       vol->name);
        return ret;
    }

    rbd_image_info_t info;
    if (rbd_stat(image, &info, sizeof(info)) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("failed to stat the RBD image"));
        goto cleanup;
    }

    VIR_DEBUG("Refreshed RBD image %s/%s (size: %llu obj_size: %llu num_objs: %llu)",
              pool->def->source.name, vol->name, (unsigned long long)info.size,
              (unsigned long long)info.obj_size,
              (unsigned long long)info.num_objs);

    vol->capacity = info.size;
    vol->allocation = info.obj_size * info.num_objs;
    vol->type = VIR_STORAGE_VOL_NETWORK;

    VIR_FREE(vol->target.path);
    if (virAsprintf(&vol->target.path, "%s/%s",
                    pool->def->source.name,
                    vol->name) == -1) {
        virReportOOMError();
        goto cleanup;
    }

    VIR_FREE(vol->key);
    if (virAsprintf(&vol->key, "%s/%s",
                    pool->def->source.name,
                    vol->name) == -1) {
        virReportOOMError();
        goto cleanup;
    }

    ret = 0;

cleanup:
    rbd_close(image);
    return ret;
}
예제 #10
0
static int virStorageBackendRBDResizeVol(virConnectPtr conn ATTRIBUTE_UNUSED,
        virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
        virStorageVolDefPtr vol,
        unsigned long long capacity,
        unsigned int flags)
{
    virStorageBackendRBDStatePtr ptr;
    ptr.cluster = NULL;
    ptr.ioctx = NULL;
    rbd_image_t image = NULL;
    int ret = -1;

    virCheckFlags(0, -1);

    if (virStorageBackendRBDOpenRADOSConn(&ptr, conn, pool) < 0) {
        goto cleanup;
    }

    if (rados_ioctx_create(ptr.cluster,
                           pool->def->source.name, &ptr.ioctx) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("failed to create the RBD IoCTX. Does the pool '%s' exist?"),
                       pool->def->source.name);
        goto cleanup;
    }

    if (rbd_open(ptr.ioctx, vol->name, &image, NULL) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("failed to open the RBD image '%s'"),
                       vol->name);
        goto cleanup;
    }

    if (rbd_resize(image, capacity) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("failed to resize the RBD image '%s'"),
                       vol->name);
        goto cleanup;
    }

    ret = 0;

cleanup:
    if (image != NULL)
        rbd_close(image);
    virStorageBackendRBDCloseRADOSConn(ptr);
    return ret;
}
예제 #11
0
static int virStorageBackendRBDResizeVol(virConnectPtr conn ATTRIBUTE_UNUSED,
                                     virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
                                     virStorageVolDefPtr vol,
                                     unsigned long long capacity,
                                     unsigned int flags)
{
    virStorageBackendRBDState ptr;
    ptr.cluster = NULL;
    ptr.ioctx = NULL;
    rbd_image_t image = NULL;
    int ret = -1;
    int r = 0;

    virCheckFlags(0, -1);

    if (virStorageBackendRBDOpenRADOSConn(&ptr, conn, pool) < 0) {
        goto cleanup;
    }

    if (virStorageBackendRBDOpenIoCTX(&ptr, pool) < 0) {
        goto cleanup;
    }

    r = rbd_open(ptr.ioctx, vol->name, &image, NULL);
    if (r < 0) {
       virReportSystemError(-r, _("failed to open the RBD image '%s'"),
                            vol->name);
       goto cleanup;
    }

    r = rbd_resize(image, capacity);
    if (r < 0) {
        virReportSystemError(-r, _("failed to resize the RBD image '%s'"),
                             vol->name);
        goto cleanup;
    }

    ret = 0;

cleanup:
    if (image != NULL)
       rbd_close(image);
    virStorageBackendRBDCloseRADOSConn(&ptr);
    return ret;
}
예제 #12
0
파일: fsx.c 프로젝트: BillTheBest/ceph
void
docloseopen(void)
{
	int ret;

	if (testcalls <= simulatedopcount)
		return;

	if (debug)
		prt("%lu close/open\n", testcalls);
	if ((ret = rbd_close(image)) < 0) {
		prterrcode("docloseopen: close", ret);
		report_failure(180);
	}
	ret = rbd_open(ioctx, iname, &image, NULL);
	if (ret < 0) {
		prterrcode("docloseopen: open", ret);
		report_failure(181);
	}
}
예제 #13
0
파일: fsx.c 프로젝트: CzBiX/ceph
int
__librbd_close(struct rbd_ctx *ctx)
{
	int ret;

	assert(ctx->name && ctx->image);

	ret = rbd_close(ctx->image);
	if (ret < 0) {
		prt("rbd_close(%s) failed\n", ctx->name);
		return ret;
	}

	free((void *)ctx->name);

	ctx->name = NULL;
	ctx->image = NULL;

	return 0;
}
예제 #14
0
static int qemu_rbd_open(BlockDriverState *bs, const char *filename, int flags)
{
    BDRVRBDState *s = bs->opaque;
    char pool[RBD_MAX_POOL_NAME_SIZE];
    char snap_buf[RBD_MAX_SNAP_NAME_SIZE];
    char conf[RBD_MAX_CONF_SIZE];
    char clientname_buf[RBD_MAX_CONF_SIZE];
    char *clientname;
    int r;

    if (qemu_rbd_parsename(filename, pool, sizeof(pool),
                           snap_buf, sizeof(snap_buf),
                           s->name, sizeof(s->name),
                           conf, sizeof(conf)) < 0) {
        return -EINVAL;
    }

    clientname = qemu_rbd_parse_clientname(conf, clientname_buf);
    r = rados_create(&s->cluster, clientname);
    if (r < 0) {
        error_report("error initializing");
        return r;
    }

    s->snap = NULL;
    if (snap_buf[0] != '\0') {
        s->snap = g_strdup(snap_buf);
    }

    /*
     * Fallback to more conservative semantics if setting cache
     * options fails. Ignore errors from setting rbd_cache because the
     * only possible error is that the option does not exist, and
     * librbd defaults to no caching. If write through caching cannot
     * be set up, fall back to no caching.
     */
    if (flags & BDRV_O_NOCACHE) {
        rados_conf_set(s->cluster, "rbd_cache", "false");
    } else {
        rados_conf_set(s->cluster, "rbd_cache", "true");
    }

    if (strstr(conf, "conf=") == NULL) {
        /* try default location, but ignore failure */
        rados_conf_read_file(s->cluster, NULL);
    }

    if (conf[0] != '\0') {
        r = qemu_rbd_set_conf(s->cluster, conf);
        if (r < 0) {
            error_report("error setting config options");
            goto failed_shutdown;
        }
    }

    r = rados_connect(s->cluster);
    if (r < 0) {
        error_report("error connecting");
        goto failed_shutdown;
    }

    r = rados_ioctx_create(s->cluster, pool, &s->io_ctx);
    if (r < 0) {
        error_report("error opening pool %s", pool);
        goto failed_shutdown;
    }

    r = rbd_open(s->io_ctx, s->name, &s->image, s->snap);
    if (r < 0) {
        error_report("error reading header from %s", s->name);
        goto failed_open;
    }

    bs->read_only = (s->snap != NULL);

    s->event_reader_pos = 0;
    r = qemu_pipe(s->fds);
    if (r < 0) {
        error_report("error opening eventfd");
        goto failed;
    }
    fcntl(s->fds[0], F_SETFL, O_NONBLOCK);
    fcntl(s->fds[1], F_SETFL, O_NONBLOCK);
    qemu_aio_set_fd_handler(s->fds[RBD_FD_READ], qemu_rbd_aio_event_reader,
                            NULL, qemu_rbd_aio_flush_cb, s);


    return 0;

failed:
    rbd_close(s->image);
failed_open:
    rados_ioctx_destroy(s->io_ctx);
failed_shutdown:
    rados_shutdown(s->cluster);
    g_free(s->snap);
    return r;
}
예제 #15
0
파일: rbd.c 프로젝트: CTU-IIG/qemu
static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
                         Error **errp)
{
    BDRVRBDState *s = bs->opaque;
    BlockdevOptionsRbd *opts = NULL;
    const QDictEntry *e;
    Error *local_err = NULL;
    char *keypairs, *secretid;
    int r;

    keypairs = g_strdup(qdict_get_try_str(options, "=keyvalue-pairs"));
    if (keypairs) {
        qdict_del(options, "=keyvalue-pairs");
    }

    secretid = g_strdup(qdict_get_try_str(options, "password-secret"));
    if (secretid) {
        qdict_del(options, "password-secret");
    }

    r = qemu_rbd_convert_options(options, &opts, &local_err);
    if (local_err) {
        /* If keypairs are present, that means some options are present in
         * the modern option format.  Don't attempt to parse legacy option
         * formats, as we won't support mixed usage. */
        if (keypairs) {
            error_propagate(errp, local_err);
            goto out;
        }

        /* If the initial attempt to convert and process the options failed,
         * we may be attempting to open an image file that has the rbd options
         * specified in the older format consisting of all key/value pairs
         * encoded in the filename.  Go ahead and attempt to parse the
         * filename, and see if we can pull out the required options. */
        r = qemu_rbd_attempt_legacy_options(options, &opts, &keypairs);
        if (r < 0) {
            /* Propagate the original error, not the legacy parsing fallback
             * error, as the latter was just a best-effort attempt. */
            error_propagate(errp, local_err);
            goto out;
        }
        /* Take care whenever deciding to actually deprecate; once this ability
         * is removed, we will not be able to open any images with legacy-styled
         * backing image strings. */
        warn_report("RBD options encoded in the filename as keyvalue pairs "
                    "is deprecated");
    }

    /* Remove the processed options from the QDict (the visitor processes
     * _all_ options in the QDict) */
    while ((e = qdict_first(options))) {
        qdict_del(options, e->key);
    }

    r = qemu_rbd_connect(&s->cluster, &s->io_ctx, opts,
                         !(flags & BDRV_O_NOCACHE), keypairs, secretid, errp);
    if (r < 0) {
        goto out;
    }

    s->snap = g_strdup(opts->snapshot);
    s->image_name = g_strdup(opts->image);

    /* rbd_open is always r/w */
    r = rbd_open(s->io_ctx, s->image_name, &s->image, s->snap);
    if (r < 0) {
        error_setg_errno(errp, -r, "error reading header from %s",
                         s->image_name);
        goto failed_open;
    }

    /* If we are using an rbd snapshot, we must be r/o, otherwise
     * leave as-is */
    if (s->snap != NULL) {
        r = bdrv_apply_auto_read_only(bs, "rbd snapshots are read-only", errp);
        if (r < 0) {
            rbd_close(s->image);
            goto failed_open;
        }
    }

    r = 0;
    goto out;

failed_open:
    rados_ioctx_destroy(s->io_ctx);
    g_free(s->snap);
    g_free(s->image_name);
    rados_shutdown(s->cluster);
out:
    qapi_free_BlockdevOptionsRbd(opts);
    g_free(keypairs);
    g_free(secretid);
    return r;
}
예제 #16
0
파일: testlibrbd.c 프로젝트: tcloud/ceph
void test_io_to_snapshot(rados_ioctx_t io_ctx, rbd_image_t image, size_t isize)
{
  int i, r;
  rbd_image_t image_at_snap;
  char orig_data[TEST_IO_TO_SNAP_SIZE + 1];
  char test_data[TEST_IO_TO_SNAP_SIZE + 1];

  for (i = 0; i < TEST_IO_TO_SNAP_SIZE - 1; ++i)
    test_data[i] = (char) (i + 48);
  test_data[TEST_IO_TO_SNAP_SIZE] = '\0';
  orig_data[TEST_IO_TO_SNAP_SIZE] = '\0';

  r = rbd_read(image, 0, TEST_IO_TO_SNAP_SIZE, orig_data);
  assert(r == TEST_IO_TO_SNAP_SIZE);

  test_ls_snaps(image, 0);
  test_create_snap(image, "orig");
  test_ls_snaps(image, 1, "orig", isize);
  read_test_data(image, orig_data, 0, TEST_IO_TO_SNAP_SIZE);

  printf("write test data!\n");
  write_test_data(image, test_data, 0, TEST_IO_TO_SNAP_SIZE);
  test_create_snap(image, "written");
  test_ls_snaps(image, 2, "orig", isize, "written", isize);

  read_test_data(image, test_data, 0, TEST_IO_TO_SNAP_SIZE);

  rbd_snap_set(image, "orig");
  read_test_data(image, orig_data, 0, TEST_IO_TO_SNAP_SIZE);

  rbd_snap_set(image, "written");
  read_test_data(image, test_data, 0, TEST_IO_TO_SNAP_SIZE);

  rbd_snap_set(image, "orig");

  r = rbd_write(image, 0, TEST_IO_TO_SNAP_SIZE, test_data);
  printf("write to snapshot returned %d\n", r);
  assert(r < 0);
  printf("%s\n", strerror(-r));

  read_test_data(image, orig_data, 0, TEST_IO_TO_SNAP_SIZE);
  rbd_snap_set(image, "written");
  read_test_data(image, test_data, 0, TEST_IO_TO_SNAP_SIZE);

  r = rbd_snap_rollback(image, "orig");
  printf("rbd_snap_rollback returned %d\n", r);
  assert(r >= 0);

  r = rbd_snap_set(image, NULL);
  assert(r == 0);
  write_test_data(image, test_data, 0, TEST_IO_TO_SNAP_SIZE);

  printf("opening testimg@orig\n");
  assert(rbd_open(io_ctx, TEST_IMAGE, &image_at_snap, "orig") >= 0);
  read_test_data(image_at_snap, orig_data, 0, TEST_IO_TO_SNAP_SIZE);
  r = rbd_write(image_at_snap, 0, TEST_IO_TO_SNAP_SIZE, test_data);
  printf("write to snapshot returned %d\n", r);
  assert(r < 0);
  printf("%s\n", strerror(-r));
  assert(rbd_close(image_at_snap) == 0);

  test_ls_snaps(image, 2, "orig", isize, "written", isize);
  test_delete_snap(image, "written");
  test_ls_snaps(image, 1, "orig", isize);
  test_delete_snap(image, "orig");
  test_ls_snaps(image, 0);
}
예제 #17
0
파일: rbd.c 프로젝트: dorlaor/qemu
static int qemu_rbd_open(BlockDriverState *bs, const char *filename, int flags)
{
    BDRVRBDState *s = bs->opaque;
    char pool[RBD_MAX_POOL_NAME_SIZE];
    char snap_buf[RBD_MAX_SNAP_NAME_SIZE];
    char conf[RBD_MAX_CONF_SIZE];
    char clientname_buf[RBD_MAX_CONF_SIZE];
    char *clientname;
    int r;

    if (qemu_rbd_parsename(filename, pool, sizeof(pool),
                           snap_buf, sizeof(snap_buf),
                           s->name, sizeof(s->name),
                           conf, sizeof(conf)) < 0) {
        return -EINVAL;
    }

    clientname = qemu_rbd_parse_clientname(conf, clientname_buf);
    r = rados_create(&s->cluster, clientname);
    if (r < 0) {
        error_report("error initializing");
        return r;
    }

    s->snap = NULL;
    if (snap_buf[0] != '\0') {
        s->snap = g_strdup(snap_buf);
    }

    if (strstr(conf, "conf=") == NULL) {
        /* try default location, but ignore failure */
        rados_conf_read_file(s->cluster, NULL);
    }

    if (conf[0] != '\0') {
        r = qemu_rbd_set_conf(s->cluster, conf);
        if (r < 0) {
            error_report("error setting config options");
            goto failed_shutdown;
        }
    }

    r = rados_connect(s->cluster);
    if (r < 0) {
        error_report("error connecting");
        goto failed_shutdown;
    }

    r = rados_ioctx_create(s->cluster, pool, &s->io_ctx);
    if (r < 0) {
        error_report("error opening pool %s", pool);
        goto failed_shutdown;
    }

    r = rbd_open(s->io_ctx, s->name, &s->image, s->snap);
    if (r < 0) {
        error_report("error reading header from %s", s->name);
        goto failed_open;
    }

    bs->read_only = (s->snap != NULL);

    s->event_reader_pos = 0;
    r = qemu_pipe(s->fds);
    if (r < 0) {
        error_report("error opening eventfd");
        goto failed;
    }
    fcntl(s->fds[0], F_SETFL, O_NONBLOCK);
    fcntl(s->fds[1], F_SETFL, O_NONBLOCK);
    qemu_aio_set_fd_handler(s->fds[RBD_FD_READ], qemu_rbd_aio_event_reader,
                            NULL, qemu_rbd_aio_flush_cb, NULL, s);


    return 0;

failed:
    rbd_close(s->image);
failed_open:
    rados_ioctx_destroy(s->io_ctx);
failed_shutdown:
    rados_shutdown(s->cluster);
    g_free(s->snap);
    return r;
}