void test_io(rados_ioctx_t io, rbd_image_t image) { char test_data[TEST_IO_SIZE + 1]; int i; for (i = 0; i < TEST_IO_SIZE; ++i) { test_data[i] = (char) (rand() % (126 - 33) + 33); } test_data[TEST_IO_SIZE] = '\0'; for (i = 0; i < 5; ++i) write_test_data(image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE); for (i = 5; i < 10; ++i) aio_write_test_data(image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE); for (i = 0; i < 5; ++i) read_test_data(image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE); for (i = 5; i < 10; ++i) aio_read_test_data(image, test_data, TEST_IO_SIZE * i, TEST_IO_SIZE); rbd_image_info_t info; rbd_completion_t comp; assert(rbd_stat(image, &info, sizeof(info)) == 0); assert(rbd_write(image, info.size, 1, test_data) == -EINVAL); assert(rbd_read(image, info.size, 1, test_data) == -EINVAL); rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp); assert(rbd_aio_write(image, info.size, 1, test_data, comp) == -EINVAL); assert(rbd_aio_read(image, info.size, 1, test_data, comp) == -EINVAL); }
static int rbdfs_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { size_t numread; struct rbd_openimage *rbd; if (!gotrados) return -ENXIO; rbd = &opentbl[fi->fh]; numread = 0; while (size > 0) { ssize_t ret; ret = rbd_read(rbd->image, offset, size, buf); if (ret <= 0) break; buf += ret; size -= ret; offset += ret; numread += ret; } return numread; }
ssize_t librbd_read(struct rbd_ctx *ctx, uint64_t off, size_t len, void *buf) { ssize_t n; n = rbd_read(ctx->image, off, len, buf); if (n < 0) prt("rbd_read(%llu, %zu) failed\n", off, len); return n; }
int main(int argc, char* argv[]) { int err; rados_t cluster; rados_ioctx_t io; rbd_image_t image; char *poolname = "pool100"; char buf[IMAGE_BUF_SIZE] = {0}; err = rados_create(&cluster, NULL); if (err < 0) { fprintf(stderr, "%s: cannot create a cluster handle: %s\n", argv[0], strerror(-err)); exit(1); } err = rados_conf_read_file(cluster, "/etc/ceph/ceph.conf"); if (err < 0) { fprintf(stderr, "%s: cannot read config file: %s\n", argv[0], strerror(-err)); exit(1); } err = rados_connect(cluster); if (err < 0) { fprintf(stderr, "%s: cannot connect to cluster: %s\n", argv[0], strerror(-err)); exit(1); } err = rados_ioctx_create(cluster, poolname, &io); if (err < 0) { fprintf(stderr, "%s: cannot open rados pool %s: %s\n", argv[0], poolname, strerror(-err)); rados_shutdown(cluster); exit(1); } err = rbd_open(io, "user1_image2", &image, NULL); if (err < 0){ fprintf(stderr, "open image failed: %s\n", strerror(-err)); goto out; } err = rbd_read(image, IMAGE_BUF_SIZE*2, IMAGE_BUF_SIZE, buf); if (err < 0) { fprintf(stderr, "%s: cannot read image: %s\n", poolname, strerror(-err)); }else{ fprintf(stderr, "read image return :%d\n", err); } out: rados_ioctx_destroy(io); rados_shutdown(cluster); return 0; }
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); } }
void read_test_data(rbd_image_t image, const char *expected, uint64_t off, size_t len) { ssize_t read; char *result; assert((result = malloc(sizeof(result) * (len + 1))) != 0); read = rbd_read(image, off, len, result); printf("read: %d\n", (int) read); assert(read == (ssize_t)len); result[len] = '\0'; printf("read: %s\nexpected: %s\n", result, expected); assert(memcmp(result, expected, len) == 0); free(result); }
void doread(unsigned offset, unsigned size) { int ret; offset -= offset % readbdy; if (o_direct) size -= size % readbdy; if (size == 0) { if (!quiet && testcalls > simulatedopcount && !o_direct) prt("skipping zero size read\n"); log4(OP_SKIPPED, OP_READ, offset, size); return; } if (size + offset > file_size) { if (!quiet && testcalls > simulatedopcount) prt("skipping seek/read past end of file\n"); log4(OP_SKIPPED, OP_READ, offset, size); return; } log4(OP_READ, offset, size, 0); if (testcalls <= simulatedopcount) return; if (!quiet && ((progressinterval && testcalls % progressinterval == 0) || (debug && (monitorstart == -1 || (offset + size > monitorstart && (monitorend == -1 || offset <= monitorend)))))) prt("%lu read\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls, offset, offset + size - 1, size); ret = rbd_read(image, offset, size, temp_buf); if (ret != (int)size) { if (ret < 0) prterrcode("doread: read", ret); else prt("short read: 0x%x bytes instead of 0x%x\n", ret, size); report_failure(141); } check_buffers(offset, size); }
static void bs_rbd_request(struct scsi_cmd *cmd) { int ret; uint32_t length; int result = SAM_STAT_GOOD; uint8_t key; uint16_t asc; #if 0 /* * This should go in the sense data on error for COMPARE_AND_WRITE, but * there doesn't seem to be any attempt to do so... */ uint32_t info = 0; #endif char *tmpbuf; size_t blocksize; uint64_t offset = cmd->offset; uint32_t tl = cmd->tl; int do_verify = 0; int i; char *ptr; const char *write_buf = NULL; ret = length = 0; key = asc = 0; struct active_rbd *rbd = RBDP(cmd->dev->fd); switch (cmd->scb[0]) { case ORWRITE_16: length = scsi_get_out_length(cmd); tmpbuf = malloc(length); if (!tmpbuf) { result = SAM_STAT_CHECK_CONDITION; key = HARDWARE_ERROR; asc = ASC_INTERNAL_TGT_FAILURE; break; } ret = rbd_read(rbd->rbd_image, offset, length, tmpbuf); if (ret != length) { set_medium_error(&result, &key, &asc); free(tmpbuf); break; } ptr = scsi_get_out_buffer(cmd); for (i = 0; i < length; i++) ptr[i] |= tmpbuf[i]; free(tmpbuf); write_buf = scsi_get_out_buffer(cmd); goto write; case COMPARE_AND_WRITE: /* Blocks are transferred twice, first the set that * we compare to the existing data, and second the set * to write if the compare was successful. */ length = scsi_get_out_length(cmd) / 2; if (length != cmd->tl) { result = SAM_STAT_CHECK_CONDITION; key = ILLEGAL_REQUEST; asc = ASC_INVALID_FIELD_IN_CDB; break; } tmpbuf = malloc(length); if (!tmpbuf) { result = SAM_STAT_CHECK_CONDITION; key = HARDWARE_ERROR; asc = ASC_INTERNAL_TGT_FAILURE; break; } ret = rbd_read(rbd->rbd_image, offset, length, tmpbuf); if (ret != length) { set_medium_error(&result, &key, &asc); free(tmpbuf); break; } if (memcmp(scsi_get_out_buffer(cmd), tmpbuf, length)) { uint32_t pos = 0; char *spos = scsi_get_out_buffer(cmd); char *dpos = tmpbuf; /* * Data differed, this is assumed to be 'rare' * so use a much more expensive byte-by-byte * comparasion to find out at which offset the * data differs. */ for (pos = 0; pos < length && *spos++ == *dpos++; pos++) ; #if 0 /* See comment above at declaration */ info = pos; #endif result = SAM_STAT_CHECK_CONDITION; key = MISCOMPARE; asc = ASC_MISCOMPARE_DURING_VERIFY_OPERATION; free(tmpbuf); break; } /* no DPO bit (cache retention advice) support */ free(tmpbuf); write_buf = scsi_get_out_buffer(cmd) + length; goto write; case SYNCHRONIZE_CACHE: case SYNCHRONIZE_CACHE_16: /* TODO */ length = (cmd->scb[0] == SYNCHRONIZE_CACHE) ? 0 : 0; if (cmd->scb[1] & 0x2) { result = SAM_STAT_CHECK_CONDITION; key = ILLEGAL_REQUEST; asc = ASC_INVALID_FIELD_IN_CDB; } else bs_sync_sync_range(cmd, length, &result, &key, &asc); break; case WRITE_VERIFY: case WRITE_VERIFY_12: case WRITE_VERIFY_16: do_verify = 1; case WRITE_6: case WRITE_10: case WRITE_12: case WRITE_16: length = scsi_get_out_length(cmd); write_buf = scsi_get_out_buffer(cmd); write: ret = rbd_write(rbd->rbd_image, offset, length, write_buf); if (ret == length) { struct mode_pg *pg; /* * it would be better not to access to pg * directy. */ pg = find_mode_page(cmd->dev, 0x08, 0); if (pg == NULL) { result = SAM_STAT_CHECK_CONDITION; key = ILLEGAL_REQUEST; asc = ASC_INVALID_FIELD_IN_CDB; break; } if (((cmd->scb[0] != WRITE_6) && (cmd->scb[1] & 0x8)) || !(pg->mode_data[0] & 0x04)) bs_sync_sync_range(cmd, length, &result, &key, &asc); } else set_medium_error(&result, &key, &asc); if (do_verify) goto verify; break; case WRITE_SAME: case WRITE_SAME_16: /* WRITE_SAME used to punch hole in file */ if (cmd->scb[1] & 0x08) { ret = rbd_discard(rbd->rbd_image, offset, tl); if (ret != 0) { eprintf("Failed to punch hole for WRITE_SAME" " command\n"); result = SAM_STAT_CHECK_CONDITION; key = HARDWARE_ERROR; asc = ASC_INTERNAL_TGT_FAILURE; break; } break; } while (tl > 0) { blocksize = 1 << cmd->dev->blk_shift; tmpbuf = scsi_get_out_buffer(cmd); switch (cmd->scb[1] & 0x06) { case 0x02: /* PBDATA==0 LBDATA==1 */ put_unaligned_be32(offset, tmpbuf); break; case 0x04: /* PBDATA==1 LBDATA==0 */ /* physical sector format */ put_unaligned_be64(offset, tmpbuf); break; } ret = rbd_write(rbd->rbd_image, offset, blocksize, tmpbuf); if (ret != blocksize) set_medium_error(&result, &key, &asc); offset += blocksize; tl -= blocksize; } break; case READ_6: case READ_10: case READ_12: case READ_16: length = scsi_get_in_length(cmd); ret = rbd_read(rbd->rbd_image, offset, length, scsi_get_in_buffer(cmd)); if (ret != length) set_medium_error(&result, &key, &asc); break; case PRE_FETCH_10: case PRE_FETCH_16: break; case VERIFY_10: case VERIFY_12: case VERIFY_16: verify: length = scsi_get_out_length(cmd); tmpbuf = malloc(length); if (!tmpbuf) { result = SAM_STAT_CHECK_CONDITION; key = HARDWARE_ERROR; asc = ASC_INTERNAL_TGT_FAILURE; break; } ret = rbd_read(rbd->rbd_image, offset, length, tmpbuf); if (ret != length) set_medium_error(&result, &key, &asc); else if (memcmp(scsi_get_out_buffer(cmd), tmpbuf, length)) { result = SAM_STAT_CHECK_CONDITION; key = MISCOMPARE; asc = ASC_MISCOMPARE_DURING_VERIFY_OPERATION; } free(tmpbuf); break; case UNMAP: if (!cmd->dev->attrs.thinprovisioning) { result = SAM_STAT_CHECK_CONDITION; key = ILLEGAL_REQUEST; asc = ASC_INVALID_FIELD_IN_CDB; break; } length = scsi_get_out_length(cmd); tmpbuf = scsi_get_out_buffer(cmd); if (length < 8) break; length -= 8; tmpbuf += 8; while (length >= 16) { offset = get_unaligned_be64(&tmpbuf[0]); offset = offset << cmd->dev->blk_shift; tl = get_unaligned_be32(&tmpbuf[8]); tl = tl << cmd->dev->blk_shift; if (offset + tl > cmd->dev->size) { eprintf("UNMAP beyond EOF\n"); result = SAM_STAT_CHECK_CONDITION; key = ILLEGAL_REQUEST; asc = ASC_LBA_OUT_OF_RANGE; break; } if (tl > 0) { if (rbd_discard(rbd->rbd_image, offset, tl) != 0) { eprintf("Failed to punch hole for" " UNMAP at offset:%" PRIu64 " length:%d\n", offset, tl); result = SAM_STAT_CHECK_CONDITION; key = HARDWARE_ERROR; asc = ASC_INTERNAL_TGT_FAILURE; break; } } length -= 16; tmpbuf += 16; } break; default: break; } dprintf("io done %p %x %d %u\n", cmd, cmd->scb[0], ret, length); scsi_set_result(cmd, result); if (result != SAM_STAT_GOOD) { eprintf("io error %p %x %d %d %" PRIu64 ", %m\n", cmd, cmd->scb[0], ret, length, offset); sense_data_build(cmd, key, asc); } }
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); }