Beispiel #1
0
static void
pool_create(const char *path, size_t bsize, size_t poolsize, unsigned mode)
{
	PMEMblkpool *pbp = pmemblk_create(path, bsize, poolsize, mode);

	if (pbp == NULL)
		UT_OUT("!%s: pmemblk_create", path);
	else {
		struct stat stbuf;
		STAT(path, &stbuf);

		UT_OUT("%s: file size %zu usable blocks %zu mode 0%o",
				path, stbuf.st_size,
				pmemblk_nblock(pbp),
				stbuf.st_mode & 0777);

		pmemblk_close(pbp);

		int result = pmemblk_check(path, bsize);

		if (result < 0)
			UT_OUT("!%s: pmemblk_check", path);
		else if (result == 0)
			UT_OUT("%s: pmemblk_check: not consistent", path);
		else
			UT_ASSERTeq(pmemblk_check(path, bsize * 2), -1);
	}
}
Beispiel #2
0
int
main(int argc, char *argv[])
{
	START(argc, argv, "blk_nblock");

	if (argc < 2)
		FATAL("usage: %s bsize:file...", argv[0]);

	/* map each file argument with the given map type */
	for (int arg = 1; arg < argc; arg++) {
		char *fname;
		size_t bsize = strtoul(argv[arg], &fname, 0);
		if (*fname != ':')
			FATAL("usage: %s bsize:file...", argv[0]);
		fname++;

		PMEMblkpool *handle;
		handle = pmemblk_create(fname, bsize, 0, S_IWUSR | S_IRUSR);
		if (handle == NULL) {
			OUT("!%s: pmemblk_create", fname);
		} else {
			OUT("%s: block size %zu usable blocks: %zu",
					fname, bsize, pmemblk_nblock(handle));
			ASSERTeq(pmemblk_bsize(handle), bsize);
			pmemblk_close(handle);
			int result = pmemblk_check(fname, bsize);
			if (result < 0)
				OUT("!%s: pmemblk_check", fname);
			else if (result == 0)
				OUT("%s: pmemblk_check: not consistent", fname);
			else {
				ASSERTeq(pmemblk_check(fname, bsize + 1), -1);
				ASSERTeq(pmemblk_check(fname, 0), 1);

				handle = pmemblk_open(fname, 0);
				ASSERTeq(pmemblk_bsize(handle), bsize);
				pmemblk_close(handle);
			}
		}
	}

	DONE(NULL);
}
Beispiel #3
0
static void
pool_open(const char *path, size_t bsize)
{
	PMEMblkpool *pbp = pmemblk_open(path, bsize);
	if (pbp == NULL)
		UT_OUT("!%s: pmemblk_open", path);
	else {
		UT_OUT("%s: pmemblk_open: Success", path);
		pmemblk_close(pbp);
	}
}
Beispiel #4
0
int
main(int argc, char *argv[])
{
	PMEMblkpool *pbp;
	struct asset asset;
	int assetid;

	if (argc < 4) {
		fprintf(stderr, "usage: %s assetdb asset-ID name\n", argv[0]);
		exit(1);
	}

	const char *path = argv[1];
	assetid = atoi(argv[2]);

	/* open an array of atomically writable elements */
	if ((pbp = pmemblk_open(path, sizeof (struct asset))) == NULL) {
		perror("pmemblk_open");
		exit(1);
	}

	/* read a required element in */
	if (pmemblk_read(pbp, &asset, (off_t)assetid) < 0) {
		perror("pmemblk_read");
		exit(1);
	}

	/* check if it contains any data */
	if ((asset.state != ASSET_FREE) &&
		(asset.state != ASSET_CHECKED_OUT)) {
		fprintf(stderr, "Asset ID %d not found", assetid);
		exit(1);
	}

	if (asset.state == ASSET_CHECKED_OUT) {
		fprintf(stderr, "Asset ID %d already checked out\n", assetid);
		exit(1);
	}

	/* update user name, set checked out state, and take timestamp */
	strncpy(asset.user, argv[3], ASSET_USER_NAME_MAX - 1);
	asset.user[ASSET_USER_NAME_MAX - 1] = '\0';
	asset.state = ASSET_CHECKED_OUT;
	time(&asset.time);

	/* put it back in the block */
	if (pmemblk_write(pbp, &asset, assetid) < 0) {
		perror("pmemblk_write");
		exit(1);
	}

	pmemblk_close(pbp);
}
Beispiel #5
0
int
main(int argc, char *argv[])
{
	PMEMblkpool *pbp;
	int assetid;
	size_t nelements;
	struct asset asset;

	if (argc < 2) {
		fprintf(stderr, "usage: %s assetdb\n", argv[0]);
		exit(1);
	}

	const char *path = argv[1];

	/* open an array of atomically writable elements */
	if ((pbp = pmemblk_open(path, sizeof(struct asset))) == NULL) {
		perror(path);
		exit(1);
	}

	/* how many elements do we have? */
	nelements = pmemblk_nblock(pbp);

	/* print out all the elements that contain assets data */
	for (assetid = 0; assetid < nelements; ++assetid) {
		if (pmemblk_read(pbp, &asset, assetid) < 0) {
			perror("pmemblk_read");
			exit(1);
		}

		if ((asset.state != ASSET_FREE) &&
			(asset.state != ASSET_CHECKED_OUT)) {
			break;
		}

		printf("Asset ID: %d\n", assetid);
		if (asset.state == ASSET_FREE)
			printf("   State: Free\n");
		else {
			printf("   State: Checked out\n");
			printf("    User: %s\n", asset.user);
			printf("    Time: %s", ctime(&asset.time));
		}
		printf("    Name: %s\n", asset.name);
	}

	pmemblk_close(pbp);
}
Beispiel #6
0
int
main(int argc, char *argv[])
{
	PMEMblkpool *pbp;
	struct asset asset;
	int assetid;

	if (argc < 3) {
		fprintf(stderr, "usage: %s assetdb asset-ID\n", argv[0]);
		exit(1);
	}

	const char *path = argv[1];
	assetid = atoi(argv[2]);
	assert(assetid > 0);

	/* open an array of atomically writable elements */
	if ((pbp = pmemblk_open(path, sizeof(struct asset))) == NULL) {
		perror("pmemblk_open");
		exit(1);
	}

	/* read a required element in */
	if (pmemblk_read(pbp, &asset, assetid) < 0) {
		perror("pmemblk_read");
		exit(1);
	}

	/* check if it contains any data */
	if ((asset.state != ASSET_FREE) &&
		(asset.state != ASSET_CHECKED_OUT)) {
		fprintf(stderr, "Asset ID %d not found\n", assetid);
		exit(1);
	}

	/* change state to free, clear user name and timestamp */
	asset.state = ASSET_FREE;
	asset.user[0] = '\0';
	asset.time = 0;

	if (pmemblk_write(pbp, &asset, assetid) < 0) {
		perror("pmemblk_write");
		exit(1);
	}

	pmemblk_close(pbp);
}
Beispiel #7
0
static void pmb_close(fio_pmemblk_file_t pmb, const bool keep)
{
	pthread_mutex_lock(&CacheLock);

	pmb->pmb_refcnt--;

	if (!keep && !pmb->pmb_refcnt) {
		pmemblk_close(pmb->pmb_pool);
		pmb->pmb_pool = NULL;
		free(pmb->pmb_filename);
		pmb->pmb_filename = NULL;
		fio_pmemblk_cache_remove(pmb);
		free(pmb);
	}

	pthread_mutex_unlock(&CacheLock);
}
Beispiel #8
0
Datei: blk.c Projekt: xguo/nvml
/*
 * pmemblk_check -- block memory pool consistency check
 */
int
pmemblk_check(const char *path, size_t bsize)
{
	LOG(3, "path \"%s\" bsize %zu", path, bsize);

	/* map the pool read-only */
	PMEMblkpool *pbp = pmemblk_open_common(path, bsize, 1);
	if (pbp == NULL)
		return -1;	/* errno set by pmemblk_open_common() */

	int retval = btt_check(pbp->bttp);
	int oerrno = errno;
	pmemblk_close(pbp);
	errno = oerrno;

	return retval;
}
Beispiel #9
0
/*
 * blk_exit -- function for de-initialization benchmark
 */
static int
blk_exit(struct benchmark *bench, struct benchmark_args *args)
{
	struct blk_bench *bb = (struct blk_bench *)pmembench_get_priv(bench);
	struct blk_args *ba = (struct blk_args *)args->opts;

	if (ba->file_io) {
		os_close(bb->fd);
	} else {
		pmemblk_close(bb->pbp);
		int result = pmemblk_check(args->fname, args->dsize);
		if (result < 0) {
			perror("pmemblk_check error");
			return -1;
		} else if (result == 0) {
			perror("pmemblk_check: not consistent");
			return -1;
		}
	}

	free(bb);
	return 0;
}
Beispiel #10
0
int
main(int argc, char *argv[])
{
	START(argc, argv, "blk_non_zero");

	if (argc < 5)
		UT_FATAL("usage: %s bsize file func [file_size] op:lba...",
				argv[0]);

	int read_arg = 1;

	Bsize = strtoul(argv[read_arg++], NULL, 0);

	const char *path = argv[read_arg++];

	PMEMblkpool *handle = NULL;
	switch (*argv[read_arg++]) {
		case 'c': {
			size_t fsize = strtoul(argv[read_arg++], NULL, 0);
			handle = pmemblk_create(path, Bsize, fsize,
					S_IRUSR | S_IWUSR);
			if (handle == NULL)
				UT_FATAL("!%s: pmemblk_create", path);
			break;
		}
		case 'o':
			handle = pmemblk_open(path, Bsize);
			if (handle == NULL)
				UT_FATAL("!%s: pmemblk_open", path);
			break;
		default:
			UT_FATAL("unrecognized command %s", argv[read_arg - 1]);
	}

	UT_OUT("%s block size %zu usable blocks %zu",
			argv[1], Bsize, pmemblk_nblock(handle));

	UT_OUT("is zeroed:\t%d", is_zeroed(path));

	/* map each file argument with the given map type */
	for (; read_arg < argc; read_arg++) {
		if (strchr("rwze", argv[read_arg][0]) == NULL ||
				argv[read_arg][1] != ':')
			UT_FATAL("op must be r: or w: or z: or e:");
		off_t lba = strtoul(&argv[read_arg][2], NULL, 0);

		unsigned char buf[Bsize];

		switch (argv[read_arg][0]) {
		case 'r':
			if (pmemblk_read(handle, buf, lba) < 0)
				UT_OUT("!read      lba %zu", lba);
			else
				UT_OUT("read      lba %zu: %s", lba,
						ident(buf));
			break;

		case 'w':
			construct(buf);
			if (pmemblk_write(handle, buf, lba) < 0)
				UT_OUT("!write     lba %zu", lba);
			else
				UT_OUT("write     lba %zu: %s", lba,
						ident(buf));
			break;

		case 'z':
			if (pmemblk_set_zero(handle, lba) < 0)
				UT_OUT("!set_zero  lba %zu", lba);
			else
				UT_OUT("set_zero  lba %zu", lba);
			break;

		case 'e':
			if (pmemblk_set_error(handle, lba) < 0)
				UT_OUT("!set_error lba %zu", lba);
			else
				UT_OUT("set_error lba %zu", lba);
			break;
		}
	}

	pmemblk_close(handle);

	int result = pmemblk_check(path, Bsize);
	if (result < 0)
		UT_OUT("!%s: pmemblk_check", path);
	else if (result == 0)
		UT_OUT("%s: pmemblk_check: not consistent", path);

	DONE(NULL);
}
Beispiel #11
0
int
main(int argc, char *argv[])
{
	START(argc, argv, "blk_recovery");

	if (argc != 5)
		FATAL("usage: %s bsize file first_lba lba", argv[0]);

	Bsize = strtoul(argv[1], NULL, 0);
	const char *path = argv[2];

	PMEMblkpool *handle;
	if ((handle = pmemblk_create(path, Bsize, 0,
			S_IWUSR | S_IRUSR)) == NULL)
		FATAL("!%s: pmemblk_create", path);

	OUT("%s block size %zu usable blocks %zu",
			argv[1], Bsize, pmemblk_nblock(handle));

	/* write the first lba */
	off_t lba = strtoul(argv[3], NULL, 0);
	unsigned char buf[Bsize];

	construct(buf);
	if (pmemblk_write(handle, buf, lba) < 0)
		FATAL("!write     lba %zu", lba);

	OUT("write     lba %zu: %s", lba, ident(buf));

	/* reach into the layout and write-protect the map */
	struct btt_info *infop = (void *)handle +
		roundup(sizeof (struct pmemblk), BLK_FORMAT_DATA_ALIGN);

	void *mapaddr = (void *)infop + le32toh(infop->mapoff);
	void *flogaddr = (void *)infop + le32toh(infop->flogoff);

	OUT("write-protecting map, length %zu", (size_t)(flogaddr - mapaddr));
	MPROTECT(mapaddr, (size_t)(flogaddr - mapaddr), PROT_READ);

	/* arrange to catch SEGV */
	struct sigaction v;
	sigemptyset(&v.sa_mask);
	v.sa_flags = 0;
	v.sa_handler = signal_handler;
	SIGACTION(SIGSEGV, &v, NULL);

	/* map each file argument with the given map type */
	lba = strtoul(argv[4], NULL, 0);

	construct(buf);

	if (!sigsetjmp(Jmp, 1)) {
		if (pmemblk_write(handle, buf, lba) < 0)
			FATAL("!write     lba %zu", lba);
		else
			FATAL("write     lba %zu: %s", lba, ident(buf));
	}

	pmemblk_close(handle);

	int result = pmemblk_check(path);
	if (result < 0)
		OUT("!%s: pmemblk_check", path);
	else if (result == 0)
		OUT("%s: pmemblk_check: not consistent", path);
	else
		OUT("%s: consistent", path);

	DONE(NULL);
}
Beispiel #12
0
static fio_pmemblk_file_t pmb_open(const char *pathspec, int flags)
{
	fio_pmemblk_file_t pmb;
	char *path = NULL;
	uint64_t bsize = 0;
	uint64_t fsize = 0;

	pmb_parse_path(pathspec, &path, &bsize, &fsize);
	if (!path)
		return NULL;

	pthread_mutex_lock(&CacheLock);

	pmb = fio_pmemblk_cache_lookup(path);
	if (!pmb) {
		/* load libpmemblk if needed */
		if (!pmemblk_open)
			if (load_libpmemblk(getenv("FIO_PMEMBLK_LIB")))
				goto error;

		pmb = malloc(sizeof(*pmb));
		if (!pmb)
			goto error;

		/* try opening existing first, create it if needed */
		pmb->pmb_pool = pmemblk_open(path, bsize);
		if (!pmb->pmb_pool && (errno == ENOENT) &&
		    (flags & PMB_CREATE) && (0 < fsize) && (0 < bsize)) {
			pmb->pmb_pool =
			    pmemblk_create(path, bsize, fsize, 0644);
		}
		if (!pmb->pmb_pool) {
			log_err
			    ("fio: enable to open pmemblk pool file (errno %d)\n",
			     errno);
			goto error;
		}

		pmb->pmb_filename = path;
		pmb->pmb_next = NULL;
		pmb->pmb_refcnt = 0;
		pmb->pmb_bsize = pmemblk_bsize(pmb->pmb_pool);
		pmb->pmb_nblocks = pmemblk_nblock(pmb->pmb_pool);

		fio_pmemblk_cache_insert(pmb);
	}

	pmb->pmb_refcnt += 1;

	pthread_mutex_unlock(&CacheLock);

	return pmb;

error:
	if (pmb) {
		if (pmb->pmb_pool)
			pmemblk_close(pmb->pmb_pool);
		pmb->pmb_pool = NULL;
		pmb->pmb_filename = NULL;
		free(pmb);
	}
	if (path)
		free(path);

	pthread_mutex_unlock(&CacheLock);
	return NULL;
}
Beispiel #13
0
int
main(int argc, char *argv[])
{
	START(argc, argv, "blk_rw");

	if (argc < 5)
		FATAL("usage: %s bsize file func op:lba...", argv[0]);

	Bsize = strtoul(argv[1], NULL, 0);

	const char *path = argv[2];

	PMEMblkpool *handle;
	switch (*argv[3]) {
		case 'c':
			handle = pmemblk_create(path, Bsize, 0,
					S_IWUSR | S_IRUSR);
			if (handle == NULL)
				FATAL("!%s: pmemblk_create", path);
			break;
		case 'o':
			handle = pmemblk_open(path, Bsize);
			if (handle == NULL)
				FATAL("!%s: pmemblk_open", path);
			break;
	}

	OUT("%s block size %zu usable blocks %zu",
			argv[1], Bsize, pmemblk_nblock(handle));

	/* map each file argument with the given map type */
	for (int arg = 4; arg < argc; arg++) {
		if (strchr("rwze", argv[arg][0]) == NULL || argv[arg][1] != ':')
			FATAL("op must be r: or w: or z: or e:");
		off_t lba = strtol(&argv[arg][2], NULL, 0);

		unsigned char buf[Bsize];

		switch (argv[arg][0]) {
		case 'r':
			if (pmemblk_read(handle, buf, lba) < 0)
				OUT("!read      lba %jd", lba);
			else
				OUT("read      lba %jd: %s", lba, ident(buf));
			break;

		case 'w':
			construct(buf);
			if (pmemblk_write(handle, buf, lba) < 0)
				OUT("!write     lba %jd", lba);
			else
				OUT("write     lba %jd: %s", lba, ident(buf));
			break;

		case 'z':
			if (pmemblk_set_zero(handle, lba) < 0)
				OUT("!set_zero  lba %jd", lba);
			else
				OUT("set_zero  lba %jd", lba);
			break;

		case 'e':
			if (pmemblk_set_error(handle, lba) < 0)
				OUT("!set_error lba %jd", lba);
			else
				OUT("set_error lba %jd", lba);
			break;
		}
	}

	pmemblk_close(handle);

	int result = pmemblk_check(path, Bsize);
	if (result < 0)
		OUT("!%s: pmemblk_check", path);
	else if (result == 0)
		OUT("%s: pmemblk_check: not consistent", path);

	DONE(NULL);
}
Beispiel #14
0
int
main(int argc, char *argv[])
{
	START(argc, argv, "out_err_mt");

	if (argc != 5)
		UT_FATAL("usage: %s filename1 filename2 filename3 dir",
				argv[0]);

	PMEMobjpool *pop = pmemobj_create(argv[1], "test",
		PMEMOBJ_MIN_POOL, 0666);
	PMEMlogpool *plp = pmemlog_create(argv[2],
		PMEMLOG_MIN_POOL, 0666);
	PMEMblkpool *pbp = pmemblk_create(argv[3],
		128, PMEMBLK_MIN_POOL, 0666);
#ifndef _WIN32
	/* XXX - vmem not implemented in windows yet */
	VMEM *vmp = vmem_create(argv[4], VMEM_MIN_POOL);
#endif

	util_init();

	pmem_check_version(10000, 0);
	pmemobj_check_version(10001, 0);
	pmemlog_check_version(10002, 0);
	pmemblk_check_version(10003, 0);
#ifndef _WIN32
	/* XXX - vmem not implemented in windows yet */
	vmem_check_version(10004, 0);
#endif
	pmempool_check_version(10005, 0);
	print_errors("version check");

	void *ptr = NULL;
	/*
	 * We are testing library error reporting and we don't want this test
	 * to fail under memcheck.
	 */
	VALGRIND_DO_DISABLE_ERROR_REPORTING;
	pmem_msync(ptr, 1);
	VALGRIND_DO_ENABLE_ERROR_REPORTING;
	print_errors("pmem_msync");

	pmemlog_append(plp, NULL, PMEMLOG_MIN_POOL);
	print_errors("pmemlog_append");

	size_t nblock = pmemblk_nblock(pbp);
	pmemblk_set_error(pbp, nblock + 1);
	print_errors("pmemblk_set_error");

#ifndef _WIN32
	/* XXX - vmem not implemented in windows yet */
	VMEM *vmp2 = vmem_create_in_region(NULL, 1);
	UT_ASSERTeq(vmp2, NULL);
	print_errors("vmem_create_in_region");
#endif

	run_mt_test(do_test);

	pmemobj_close(pop);
	pmemlog_close(plp);
	pmemblk_close(pbp);
#ifndef _WIN32
	/* XXX - vmem not implemented in windows yet */
	vmem_delete(vmp);
#endif

	PMEMpoolcheck *ppc;
	struct pmempool_check_args args = {0, };
	ppc = pmempool_check_init(&args, sizeof(args) / 2);
	UT_ASSERTeq(ppc, NULL);
	print_errors("pmempool_check_init");

	DONE(NULL);
}
Beispiel #15
0
/*
 * blk_init -- function for initialization benchmark
 */
static int
blk_init(struct blk_bench *bb, struct benchmark_args *args)
{
	struct blk_args *ba = (struct blk_args *)args->opts;
	assert(ba != NULL);

	if (ba->fsize == 0)
		ba->fsize = PMEMBLK_MIN_POOL;

	if (ba->fsize / args->dsize < args->n_threads ||
	    ba->fsize < PMEMBLK_MIN_POOL) {
		fprintf(stderr, "too small file size\n");
		return -1;
	}

	if (args->dsize >= ba->fsize) {
		fprintf(stderr, "block size bigger than file size\n");
		return -1;
	}

	if (args->is_poolset) {
		if (args->fsize < ba->fsize) {
			fprintf(stderr, "insufficient size of poolset\n");
			return -1;
		}

		ba->fsize = 0;
	}

	bb->fd = -1;
	/*
	 * Create pmemblk in order to get the number of blocks
	 * even for file-io mode.
	 */
	bb->pbp = pmemblk_create(args->fname, args->dsize, ba->fsize,
				 args->fmode);
	if (bb->pbp == NULL) {
		perror("pmemblk_create");
		return -1;
	}

	bb->nblocks = pmemblk_nblock(bb->pbp);

	if (bb->nblocks < args->n_threads) {
		fprintf(stderr, "too small file size");
		goto out_close;
	}

	if (ba->file_io) {
		pmemblk_close(bb->pbp);
		bb->pbp = NULL;

		int flags = O_RDWR | O_CREAT | O_SYNC;
#ifdef _WIN32
		flags |= O_BINARY;
#endif
		bb->fd = os_open(args->fname, flags, args->fmode);
		if (bb->fd < 0) {
			perror("open");
			return -1;
		}
	}

	bb->blocks_per_thread = bb->nblocks / args->n_threads;

	if (!ba->no_warmup) {
		if (blk_do_warmup(bb, args) != 0)
			goto out_close;
	}

	return 0;
out_close:
	if (ba->file_io)
		os_close(bb->fd);
	else
		pmemblk_close(bb->pbp);
	return -1;
}
Beispiel #16
0
int
main(int argc, char *argv[])
{
	FILE *fp;
	int len = ASSET_NAME_MAX;
	PMEMblkpool *pbp;
	int assetid = 0;
	size_t nelements;
	char *line;

	if (argc < 3) {
		fprintf(stderr, "usage: %s assetdb assetlist\n", argv[0]);
		exit(1);
	}

	const char *path_pool = argv[1];
	const char *path_list = argv[2];

	/* create pmemblk pool in existing (but as yet unmodified) file */
	pbp = pmemblk_create(path_pool, sizeof(struct asset),
			0, CREATE_MODE_RW);

	if (pbp == NULL) {
		perror(path_pool);
		exit(1);
	}

	nelements = pmemblk_nblock(pbp);

	if ((fp = fopen(path_list, "r")) == NULL) {
		perror(path_list);
		exit(1);
	}

	/*
	 * Read in all the assets from the assetfile and put them in the
	 * array, if a name of the asset is longer than ASSET_NAME_SIZE_MAX,
	 * truncate it.
	 */
	line = malloc(len);
	if (line == NULL) {
		perror("malloc");
		exit(1);
	}
	while (fgets(line, len, fp) != NULL) {
		struct asset asset;

		if (assetid >= nelements) {
			fprintf(stderr, "%s: too many assets to fit in %s "
					"(only %d assets loaded)\n",
					path_list, path_pool, assetid);
			exit(1);
		}

		memset(&asset, '\0', sizeof(asset));
		asset.state = ASSET_FREE;
		strncpy(asset.name, line, ASSET_NAME_MAX - 1);
		asset.name[ASSET_NAME_MAX - 1] = '\0';

		if (pmemblk_write(pbp, &asset, assetid) < 0) {
			perror("pmemblk_write");
			exit(1);
		}

		assetid++;
	}

	free(line);
	fclose(fp);

	pmemblk_close(pbp);
}
Beispiel #17
0
int
main(int argc, char *argv[])
{
	struct blk_arguments arguments;

	/* set the random seed value */
	srand(time(NULL));

	/* set default values */
	memset(&arguments, 0, sizeof (struct blk_arguments));
	arguments.block_size = 512;
	arguments.num_ops = 100;
	arguments.file_size = (PMEMBLK_MIN_POOL / 1024) / 1024;

	if (argp_parse(&argp, argc, argv, 0, 0, &arguments) != 0) {
		exit(1);
	}

	struct worker_info worker_params[arguments.thread_count];
	memset(worker_params, 0, sizeof (struct worker_info));

	/* set common values */
	worker_params[0].block_size = arguments.block_size;
	worker_params[0].num_ops = arguments.num_ops;
	worker_params[0].file_lanes = arguments.thread_count;

	/* file_size is provided in MB */
	unsigned long long file_size_bytes = arguments.file_size * 1024 * 1024;

	worker *thread_workers = NULL;

	/* prepare parameters specific for file/pmem */
	if (arguments.file_io) {
		/* prepare open flags */
		int flags = O_RDWR | O_CREAT | O_SYNC;
		/* create file on PMEM-aware file system */
		if ((worker_params[0].file_desc = open(arguments.file_path,
			flags, FILE_MODE)) < 0) {
			perror(arguments.file_path);
			exit(1);
		}

		/* pre-allocate file_size MB of persistent memory */
		if ((errno = posix_fallocate(worker_params[0].file_desc,
			(off_t)0, (off_t)file_size_bytes)) != 0) {
			warn("posix_fallocate");
			close(worker_params[0].file_desc);
			exit(1);
		}

		worker_params[0].num_blocks = file_size_bytes
				/ worker_params[0].block_size;
		thread_workers = file_workers;
	} else {
		worker_params[0].file_desc = -1;
		if (arguments.prep_blk_file) {
			if ((worker_params[0].handle = pmemblk_create(
				arguments.file_path,
				worker_params[0].block_size,
				(off_t)file_size_bytes, FILE_MODE)) == NULL) {
				err(1, "%s: pmemblk_open", argv[2]);
			}
		} else {
			if ((worker_params[0].handle = pmemblk_open(
					arguments.file_path,
					worker_params[0].block_size)) == NULL) {
				err(1, "%s: pmemblk_open", argv[2]);
			}

		}
		worker_params[0].num_blocks = pmemblk_nblock(
				worker_params[0].handle);
		thread_workers = pmem_workers;
	}

	/* propagate params to each info_t */
	for (int i = 1; i < arguments.thread_count; ++i) {
		memcpy(&worker_params[i], &worker_params[0],
				sizeof (struct worker_info));
		worker_params[i].thread_index = i;
		worker_params[i].seed = rand();
	}

	/* The blk mode file prep */
	if (arguments.prep_blk_file) {
		if (worker_params[0].file_desc >= 0)
			close(worker_params[0].file_desc);
		return run_threads(prep_worker, arguments.thread_count,
				worker_params);
	}

	struct measurements perf_meas;
	perf_meas.total_ops = arguments.thread_count
			* worker_params[0].num_ops;

	/* perform PMEMBLK warmup */
	if (!arguments.file_io) {
		if (run_threads(warmup_worker, arguments.thread_count,
				worker_params) != 0) {
			if (worker_params[0].file_desc >= 0)
				close(worker_params[0].file_desc);
			exit(1);
		}
	}

	for (int i = 0; i < WORKER_COUNT_MAX; ++i) {
		clock_gettime(CLOCK_MONOTONIC, &perf_meas.start_time);
		if (run_threads(thread_workers[i], arguments.thread_count,
				worker_params) != 0) {
			if (worker_params[0].file_desc >= 0)
				close(worker_params[0].file_desc);
			exit(1);
		}
		clock_gettime(CLOCK_MONOTONIC, &perf_meas.stop_time);

		calculate_stats(&perf_meas);
		printf("%f;%f;", perf_meas.total_run_time,
				perf_meas.ops_per_second);
	}

	printf("\n");

	if (worker_params[0].file_desc >= 0)
		close(worker_params[0].file_desc);

	/* cleanup and check pmem file */
	if (!arguments.file_io) {
		pmemblk_close(worker_params[0].handle);

		/* not really necessary, but check consistency */
		int result = pmemblk_check(arguments.file_path);
		if (result < 0) {
			warn("%s: pmemblk_check",
					arguments.file_path);
		} else if (result == 0) {
			warnx("%s: pmemblk_check: not consistent",
					arguments.file_path);
		}
	}

	exit(0);
}