void docloseopen(void) { char *name; int ret; if (testcalls <= simulatedopcount) return; name = strdup(ctx.name); if (debug) prt("%lu close/open\n", testcalls); ret = ops->close(&ctx); if (ret < 0) { prterrcode("docloseopen: ops->close", ret); report_failure(180); } ret = ops->open(name, &ctx); if (ret < 0) { prterrcode("docloseopen: ops->open", ret); report_failure(181); } free(name); }
void dowrite(unsigned offset, unsigned size) { ssize_t ret; off_t newsize; offset -= offset % writebdy; if (o_direct) size -= size % writebdy; if (size == 0) { if (!quiet && testcalls > simulatedopcount && !o_direct) prt("skipping zero size write\n"); log4(OP_SKIPPED, OP_WRITE, offset, size); return; } log4(OP_WRITE, offset, size, file_size); gendata(original_buf, good_buf, offset, size); if (file_size < offset + size) { newsize = ceil(((double)offset + size) / truncbdy) * truncbdy; if (file_size < newsize) memset(good_buf + file_size, '\0', newsize - file_size); file_size = newsize; if (lite) { warn("Lite file size bug in fsx!"); report_failure(149); } ret = rbd_resize(image, newsize); if (ret < 0) { prterrcode("dowrite: resize", ret); report_failure(150); } } if (testcalls <= simulatedopcount) return; if (!quiet && ((progressinterval && testcalls % progressinterval == 0) || (debug && (monitorstart == -1 || (offset + size > monitorstart && (monitorend == -1 || offset <= monitorend)))))) prt("%lu write\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls, offset, offset + size - 1, size); ret = rbd_write(image, offset, size, good_buf + offset); if (ret != size) { if (ret < 0) prterrcode("dowrite: rbd_write", ret); else prt("short write: 0x%x bytes instead of 0x%x\n", ret, size); report_failure(151); } if (flush) { doflush(offset, size); } }
void check_trunc_hack(void) { uint64_t size; int ret; ret = ops->resize(&ctx, 0ULL); if (ret < 0) prterrcode("check_trunc_hack: ops->resize pre", ret); ret = ops->resize(&ctx, TRUNC_HACK_SIZE); if (ret < 0) prterrcode("check_trunc_hack: ops->resize actual", ret); ret = ops->get_size(&ctx, &size); if (ret < 0) prterrcode("check_trunc_hack: ops->get_size", ret); if (size != TRUNC_HACK_SIZE) { prt("no extend on truncate! not posix!\n"); exit(130); } ret = ops->resize(&ctx, 0ULL); if (ret < 0) prterrcode("check_trunc_hack: ops->resize post", ret); }
void dotruncate(unsigned size) { int oldsize = file_size; int ret; size -= size % truncbdy; if (size > biggest) { biggest = size; if (!quiet && testcalls > simulatedopcount) prt("truncating to largest ever: 0x%x\n", size); } log4(OP_TRUNCATE, size, (unsigned)file_size, 0); if (size > file_size) memset(good_buf + file_size, '\0', size - file_size); else if (size < file_size) memset(good_buf + size, '\0', file_size - size); file_size = size; if (testcalls <= simulatedopcount) return; if ((progressinterval && testcalls % progressinterval == 0) || (debug && (monitorstart == -1 || monitorend == -1 || size <= monitorend))) prt("%lu trunc\tfrom 0x%x to 0x%x\n", testcalls, oldsize, size); if ((ret = rbd_resize(image, size)) < 0) { prt("rbd_resize: %x\n", size); prterrcode("dotruncate: ftruncate", ret); report_failure(160); } }
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); } }
void writefileimage() { ssize_t ret; ret = rbd_write(image, 0, file_size, good_buf); if (ret != file_size) { if (ret < 0) prterrcode("writefileimage: write", ret); else prt("short write: 0x%x bytes instead of 0x%llx\n", ret, (unsigned long long)file_size); report_failure(172); } if (lite ? 0 : (ret = rbd_resize(image, file_size)) < 0) { prt("rbd_resize: %llx\n", (unsigned long long)file_size); prterrcode("writefileimage: rbd_resize", ret); report_failure(173); } }
static bool rbd_image_has_parent(struct rbd_ctx *ctx) { int ret; ret = rbd_get_parent_info(ctx->image, NULL, 0, NULL, 0, NULL, 0); if (ret < 0 && ret != -ENOENT) { prterrcode("rbd_get_parent_info", ret); exit(1); } return !ret; }
void doflush(unsigned offset, unsigned size) { int ret; if (o_direct) return; ret = ops->flush(&ctx); if (ret < 0) prterrcode("doflush: ops->flush", ret); }
void writefileimage() { ssize_t ret; ret = ops->write(&ctx, 0, file_size, good_buf); if (ret != file_size) { if (ret < 0) prterrcode("writefileimage: ops->write", ret); else prt("short write: 0x%x bytes instead of 0x%llx\n", ret, (unsigned long long)file_size); report_failure(172); } if (!lite) { ret = ops->resize(&ctx, file_size); if (ret < 0) { prterrcode("writefileimage: ops->resize", ret); report_failure(173); } } }
void do_punch_hole(unsigned offset, unsigned length) { unsigned end_offset; int max_offset = 0; int max_len = 0; int ret; offset -= offset % holebdy; length -= length % holebdy; if (length == 0) { if (!quiet && testcalls > simulatedopcount) prt("skipping zero length punch hole\n"); log4(OP_SKIPPED, OP_PUNCH_HOLE, offset, length); return; } if (file_size <= (loff_t)offset) { if (!quiet && testcalls > simulatedopcount) prt("skipping hole punch off the end of the file\n"); log4(OP_SKIPPED, OP_PUNCH_HOLE, offset, length); return; } end_offset = offset + length; log4(OP_PUNCH_HOLE, offset, length, 0); if (testcalls <= simulatedopcount) return; if ((progressinterval && testcalls % progressinterval == 0) || (debug && (monitorstart == -1 || monitorend == -1 || end_offset <= monitorend))) { prt("%lu punch\tfrom 0x%x to 0x%x, (0x%x bytes)\n", testcalls, offset, offset+length, length); } ret = ops->discard(&ctx, (unsigned long long)offset, (unsigned long long)length); if (ret < 0) { prterrcode("do_punch_hole: ops->discard", ret); report_failure(161); } max_offset = offset < file_size ? offset : file_size; max_len = max_offset + length <= file_size ? length : file_size - max_offset; memset(good_buf + max_offset, '\0', max_len); }
void check_size(void) { rbd_image_info_t statbuf; int ret; if ((ret = rbd_stat(image, &statbuf, sizeof(statbuf))) < 0) { prterrcode("check_size: fstat", ret); } if ((uint64_t)file_size != statbuf.size) { prt("Size error: expected 0x%llx stat 0x%llx\n", (unsigned long long)file_size, (unsigned long long)statbuf.size); report_failure(120); } }
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 = ops->read(&ctx, offset, size, temp_buf); if (ret != (int)size) { if (ret < 0) prterrcode("doread: ops->read", ret); else prt("short read: 0x%x bytes instead of 0x%x\n", ret, size); report_failure(141); } check_buffers(good_buf, temp_buf, offset, size); }
void check_size(void) { uint64_t size; int ret; ret = ops->get_size(&ctx, &size); if (ret < 0) prterrcode("check_size: ops->get_size", ret); if ((uint64_t)file_size != size) { prt("Size error: expected 0x%llx stat 0x%llx\n", (unsigned long long)file_size, (unsigned long long)size); report_failure(120); } }
void do_flatten() { int ret; if (!rbd_image_has_parent(&ctx)) { log4(OP_SKIPPED, OP_FLATTEN, 0, 0); return; } log4(OP_FLATTEN, 0, 0, 0); prt("%lu flatten\n", testcalls); ret = ops->flatten(&ctx); if (ret < 0) { prterrcode("writefileimage: ops->flatten", ret); exit(177); } }
void check_clone(int clonenum) { char filename[128]; char imagename[128]; int ret, fd; struct rbd_ctx cur_ctx = RBD_CTX_INIT; struct stat file_info; char *good_buf, *temp_buf; clone_imagename(imagename, sizeof(imagename), clonenum); if ((ret = ops->open(imagename, &cur_ctx)) < 0) { prterrcode("check_clone: ops->open", ret); exit(167); } clone_filename(filename, sizeof(filename), clonenum + 1); if ((fd = open(filename, O_RDONLY)) < 0) { simple_err("check_clone: open", -errno); exit(168); } prt("checking clone #%d, image %s against file %s\n", clonenum, imagename, filename); if ((ret = fstat(fd, &file_info)) < 0) { simple_err("check_clone: fstat", -errno); exit(169); } good_buf = NULL; ret = posix_memalign((void **)&good_buf, MAX(writebdy, (int)sizeof(void *)), file_info.st_size); if (ret > 0) { prterrcode("check_clone: posix_memalign(good_buf)", -ret); exit(96); } temp_buf = NULL; ret = posix_memalign((void **)&temp_buf, MAX(readbdy, (int)sizeof(void *)), file_info.st_size); if (ret > 0) { prterrcode("check_clone: posix_memalign(temp_buf)", -ret); exit(97); } if ((ret = pread(fd, good_buf, file_info.st_size, 0)) < 0) { simple_err("check_clone: pread", -errno); exit(170); } if ((ret = ops->read(&cur_ctx, 0, file_info.st_size, temp_buf)) < 0) { prterrcode("check_clone: ops->read", ret); exit(171); } close(fd); if ((ret = ops->close(&cur_ctx)) < 0) { prterrcode("check_clone: ops->close", ret); exit(174); } check_buffers(good_buf, temp_buf, 0, file_info.st_size); unlink(filename); free(good_buf); free(temp_buf); }
void do_clone() { char filename[1024]; char imagename[1024]; char lastimagename[1024]; int ret, fd; int order = 0, stripe_unit = 0, stripe_count = 0; uint64_t newsize = file_size; log4(OP_CLONE, 0, 0, 0); ++num_clones; if (randomize_striping) { order = 18 + get_random() % 8; stripe_unit = 1ull << (order - 1 - (get_random() % 8)); stripe_count = 2 + get_random() % 14; } prt("%lu clone\t%d order %d su %d sc %d\n", testcalls, num_clones, order, stripe_unit, stripe_count); clone_imagename(imagename, sizeof(imagename), num_clones); clone_imagename(lastimagename, sizeof(lastimagename), num_clones - 1); assert(strcmp(lastimagename, ctx.name) == 0); ret = ops->clone(&ctx, "snap", imagename, &order, stripe_unit, stripe_count); if (ret < 0) { prterrcode("do_clone: ops->clone", ret); exit(165); } if (randomize_parent_overlap && rbd_image_has_parent(&ctx)) { int rand = get_random() % 16 + 1; // [1..16] if (rand < 13) { uint64_t overlap; ret = rbd_get_overlap(ctx.image, &overlap); if (ret < 0) { prterrcode("do_clone: rbd_get_overlap", ret); exit(1); } if (rand < 10) { // 9/16 newsize = overlap * ((double)rand / 10); newsize -= newsize % truncbdy; } else { // 3/16 newsize = 0; } assert(newsize != (uint64_t)file_size); prt("truncating image %s from 0x%llx (overlap 0x%llx) to 0x%llx\n", ctx.name, file_size, overlap, newsize); ret = ops->resize(&ctx, newsize); if (ret < 0) { prterrcode("do_clone: ops->resize", ret); exit(1); } } else if (rand < 15) { // 2/16 prt("flattening image %s\n", ctx.name); ret = ops->flatten(&ctx); if (ret < 0) { prterrcode("do_clone: ops->flatten", ret); exit(1); } } else { // 2/16 prt("leaving image %s intact\n", ctx.name); } } 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, newsize, fd); if ((ret = close(fd)) < 0) { simple_err("do_clone: close", -errno); exit(163); } /* * Close parent. */ if ((ret = ops->close(&ctx)) < 0) { prterrcode("do_clone: ops->close", ret); exit(174); } /* * Open freshly made clone. */ if ((ret = ops->open(imagename, &ctx)) < 0) { prterrcode("do_clone: ops->open", ret); exit(166); } if (num_clones > 1) check_clone(num_clones - 2); }