X-Git-Url: https://git.kernel.dk/?p=fio.git;a=blobdiff_plain;f=engines%2Fpmemblk.c;h=fc6358e8e11f3730fc6163127830aaf5bc1ebf7a;hp=c28a1d97d48a04567188c462748379e2b1450092;hb=HEAD;hpb=43f3cec2e958691d67404b01976f854281af6841 diff --git a/engines/pmemblk.c b/engines/pmemblk.c deleted file mode 100644 index c28a1d97..00000000 --- a/engines/pmemblk.c +++ /dev/null @@ -1,602 +0,0 @@ -/* - * pmemblk: IO engine that uses NVML libpmemblk to read and write data - * - * Copyright (C) 2016 Hewlett Packard Enterprise Development LP - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License, - * version 2 as published by the Free Software Foundation.. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307 USA - */ - - -/* - * pmemblk engine - * - * IO engine that uses libpmemblk to read and write data - * - * To build as an external engine: - * Copy pmemblk.c to the engines/ directory of the fio source code, then: - * cd .../engines/ - * gcc -Wall -shared -rdynamic -fPIC -o pmemblk.o -D_GNU_SOURCE pmemblk.c - * - * To use as an external engine: - * ioengine=/full/path/to/pmemblk.o - * - * Other relevant settings: - * iodepth=1 - * direct=1 - * thread=1 REQUIRED - * unlink=1 - * filename=/pmem0/fiotestfile,BSIZE,FSIZEMB - * - * thread must be set to 1 for pmemblk as multiple processes cannot - * open the same block pool file. - * - * iodepth should be set to 1 as pmemblk is always synchronous. - * Use numjobs to scale up. - * - * direct=1 is implied as pmemblk is always direct. - * - * Can set unlink to 1 to remove the block pool file after testing. - * - * When specifying the filename, if the block pool file does not already - * exist, then the pmemblk engine can create the pool file if you specify - * the block and file sizes. BSIZE is the block size in bytes. - * FSIZEMB is the pool file size in MB. - * - * libpmemblk.so - * By default, the pmemblk engine will let the system find the libpmemblk.so - * that it uses. You can use an alternative libpmemblk by setting the - * FIO_PMEMBLK_LIB environment variable to the full path to the desired - * libpmemblk.so. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../fio.h" - - - -/* - * libpmemblk - */ -struct PMEMblkpool_s; -typedef struct PMEMblkpool_s PMEMblkpool; - -PMEMblkpool* (*pmemblk_create_ptr)(const char*, size_t, size_t, mode_t) = NULL; -PMEMblkpool* (*pmemblk_open_ptr)(const char*, size_t) = NULL; -void (*pmemblk_close_ptr)(PMEMblkpool*) = NULL; -size_t (*pmemblk_nblock_ptr)(PMEMblkpool*) = NULL; -size_t (*pmemblk_bsize_ptr)(PMEMblkpool*) = NULL; -int (*pmemblk_read_ptr)(PMEMblkpool*, void*, off_t) = NULL; -int (*pmemblk_write_ptr)(PMEMblkpool*, const void*, off_t) = NULL; - -int -load_libpmemblk( - const char* path -) -{ - void* dl; - - if (NULL == path) - path = "libpmemblk.so"; - - dl = dlopen(path, RTLD_NOW | RTLD_NODELETE); - if (NULL == dl) - goto errorout; - - if (NULL == (pmemblk_create_ptr = dlsym(dl, "pmemblk_create"))) - goto errorout; - if (NULL == (pmemblk_open_ptr = dlsym(dl, "pmemblk_open"))) - goto errorout; - if (NULL == (pmemblk_close_ptr = dlsym(dl, "pmemblk_close"))) - goto errorout; - if (NULL == (pmemblk_nblock_ptr = dlsym(dl, "pmemblk_nblock"))) - goto errorout; - if (NULL == (pmemblk_bsize_ptr = dlsym(dl, "pmemblk_bsize"))) - goto errorout; - if (NULL == (pmemblk_read_ptr = dlsym(dl, "pmemblk_read"))) - goto errorout; - if (NULL == (pmemblk_write_ptr = dlsym(dl, "pmemblk_write"))) - goto errorout; - - return 0; - -errorout: - log_err("fio: unable to load libpmemblk: %s\n", dlerror()); - if (NULL != dl) - dlclose(dl); - - return (-1); - -} /* load_libpmemblk() */ - -#define pmemblk_create pmemblk_create_ptr -#define pmemblk_open pmemblk_open_ptr -#define pmemblk_close pmemblk_close_ptr -#define pmemblk_nblock pmemblk_nblock_ptr -#define pmemblk_bsize pmemblk_bsize_ptr -#define pmemblk_read pmemblk_read_ptr -#define pmemblk_write pmemblk_write_ptr - - -typedef struct fio_pmemblk_file* fio_pmemblk_file_t; -struct fio_pmemblk_file { - fio_pmemblk_file_t pmb_next; - char* pmb_filename; - uint64_t pmb_refcnt; - PMEMblkpool* pmb_pool; - size_t pmb_bsize; - size_t pmb_nblocks; -}; -#define FIOFILEPMBSET(_f, _v) do { \ - (_f)->engine_data = (uint64_t)(uintptr_t)(_v); \ -} while(0) -#define FIOFILEPMBGET(_f) ((fio_pmemblk_file_t)((_f)->engine_data)) - -static fio_pmemblk_file_t Cache = NULL; - -static pthread_mutex_t CacheLock = PTHREAD_MUTEX_INITIALIZER; -#define CACHE_LOCK() \ - (void)pthread_mutex_lock(&CacheLock) -#define CACHE_UNLOCK() \ - (void)pthread_mutex_unlock(&CacheLock) - -#define PMB_CREATE (0x0001) /* should create file */ - - -fio_pmemblk_file_t -fio_pmemblk_cache_lookup( - const char* filename -) -{ - fio_pmemblk_file_t i; - - for (i = Cache; i != NULL; i = i->pmb_next) - if (0 == strcmp(filename, i->pmb_filename)) - return i; - - return NULL; - -} /* fio_pmemblk_cache_lookup() */ - - -static void -fio_pmemblk_cache_insert( - fio_pmemblk_file_t pmb -) -{ - pmb->pmb_next = Cache; - Cache = pmb; - - return; - -} /* fio_pmemblk_cache_insert() */ - - -static void -fio_pmemblk_cache_remove( - fio_pmemblk_file_t pmb -) -{ - fio_pmemblk_file_t i; - - if (pmb == Cache) { - Cache = Cache->pmb_next; - pmb->pmb_next = NULL; - return; - } - - for (i = Cache; i != NULL; i = i->pmb_next) - if (pmb == i->pmb_next) { - i->pmb_next = i->pmb_next->pmb_next; - pmb->pmb_next = NULL; - return; - } - - return; - -} /* fio_pmemblk_cache_remove() */ - - -/* - * to control block size and gross file size at the libpmemblk - * level, we allow the block size and file size to be appended - * to the file name: - * - * path[,bsize,fsizemb] - * - * note that we do not use the fio option "filesize" to dictate - * the file size because we can only give libpmemblk the gross - * file size, which is different from the net or usable file - * size (which is probably what fio wants). - * - * the final path without the parameters is returned in ppath. - * the block size and file size are returned in pbsize and fsize. - * - * note that the user should specify the file size in MiB, but - * we return bytes from here. - */ -static void -pmb_parse_path( - const char* pathspec, - char** ppath, - uint64_t* pbsize, - uint64_t* pfsize -) -{ - char* path; - char* s; - uint64_t bsize; - uint64_t fsizemb; - - path = strdup(pathspec); - if (NULL == path) { - *ppath = NULL; - return; - } - - /* extract sizes, if given */ - s = strrchr(path, ','); - if (s && (fsizemb = strtoull(s+1, NULL, 10))) { - *s = 0; - s = strrchr(path, ','); - if (s && (bsize = strtoull(s+1, NULL, 10))) { - *s = 0; - *ppath = path; - *pbsize = bsize; - *pfsize = fsizemb << 20; - return; - } - } - - /* size specs not found */ - strcpy(path, pathspec); - *ppath = path; - *pbsize = 0; - *pfsize = 0; - return; - -} /* pmb_parse_path() */ - - -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 (NULL == path) - return NULL; - - CACHE_LOCK(); - - pmb = fio_pmemblk_cache_lookup(path); - - if (NULL == pmb) { - /* load libpmemblk if needed */ - if (NULL == pmemblk_open) - if (0 != load_libpmemblk(getenv("FIO_PMEMBLK_LIB"))) - goto error; - - pmb = malloc(sizeof(*pmb)); - if (NULL == pmb) - goto error; - - /* try opening existing first, create it if needed */ - pmb->pmb_pool = pmemblk_open(path, bsize); - if ((NULL == pmb->pmb_pool) && - (ENOENT == errno) && - (flags & PMB_CREATE) && - (0 < fsize) && - (0 < bsize)) { - pmb->pmb_pool = pmemblk_create(path, bsize, fsize, 0644); - } - if (NULL == 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; - - CACHE_UNLOCK(); - - return pmb; - -error: - if (NULL != pmb) { - if (NULL != pmb->pmb_pool) - pmemblk_close(pmb->pmb_pool); - pmb->pmb_pool = NULL; - pmb->pmb_filename = NULL; - free(pmb); - } - if (NULL != path) - free(path); - CACHE_UNLOCK(); - return NULL; - -} /* pmb_open() */ - - -static void -pmb_close( - fio_pmemblk_file_t pmb, - const int keep -) -{ - CACHE_LOCK(); - - pmb->pmb_refcnt--; - - if (!keep && (0 == 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); - } - - CACHE_UNLOCK(); - -} /* pmb_close() */ - - -static int -pmb_get_flags( - struct thread_data* td, - uint64_t* pflags -) -{ - static int thread_warned = 0; - static int odirect_warned = 0; - - uint64_t flags = 0; - - if (!td->o.use_thread) { - if (!thread_warned) { - thread_warned = 1; - log_err("fio: must set thread=1 for pmemblk engine\n"); - } - return 1; - } - - if (!td->o.odirect && !odirect_warned) { - odirect_warned = 1; - log_info("fio: direct == 0, but pmemblk is always direct\n"); - } - - if (td->o.allow_create) - flags |= PMB_CREATE; - - (*pflags) = flags; - return 0; - -} /* pmb_get_flags() */ - - -static int -fio_pmemblk_open_file( - struct thread_data* td, - struct fio_file* f) -{ - uint64_t flags = 0; - fio_pmemblk_file_t pmb; - - if (0 != pmb_get_flags(td, &flags)) - return 1; - - pmb = pmb_open(f->file_name, flags); - if (NULL == pmb) - return 1; - - FIOFILEPMBSET(f, pmb); - - return 0; - -} /* fio_pmemblk_open_file() */ - - -static int -fio_pmemblk_close_file( - struct thread_data fio_unused* td, - struct fio_file* f -) -{ - fio_pmemblk_file_t pmb = FIOFILEPMBGET(f); - - if (pmb) - pmb_close(pmb, 0); - - FIOFILEPMBSET(f, NULL); - - return 0; - -} /* fio_pmemblk_close_file() */ - - -static int -fio_pmemblk_get_file_size( - struct thread_data* td, - struct fio_file* f -) -{ - uint64_t flags = 0; - fio_pmemblk_file_t pmb = FIOFILEPMBGET(f); - - if (fio_file_size_known(f)) - return 0; - - if (NULL == pmb) { - if (0 != pmb_get_flags(td, &flags)) - return 1; - pmb = pmb_open(f->file_name, flags); - if (NULL == pmb) - return 1; - } - - f->real_file_size = pmb->pmb_bsize * pmb->pmb_nblocks; - - fio_file_set_size_known(f); - - if (NULL == FIOFILEPMBGET(f)) - pmb_close(pmb, 1); - - return 0; - -} /* fio_pmemblk_get_file_size() */ - - -static int -fio_pmemblk_queue( - struct thread_data* td, - struct io_u* io_u) -{ - struct fio_file* f = io_u->file; - fio_pmemblk_file_t pmb = FIOFILEPMBGET(f); - - unsigned long long off; - unsigned long len; - void* buf; - int (*blkop)(PMEMblkpool*, void*, off_t) = (void*)pmemblk_write; - - fio_ro_check(td, io_u); - - switch (io_u->ddir) { - case DDIR_READ: - blkop = pmemblk_read; - /* fall through */ - case DDIR_WRITE: - off = io_u->offset; - len = io_u->xfer_buflen; - - io_u->error = EINVAL; - if (0 != (off % pmb->pmb_bsize)) - break; - if (0 != (len % pmb->pmb_bsize)) - break; - if ((off + len) / pmb->pmb_bsize > pmb->pmb_nblocks) - break; - - io_u->error = 0; - buf = io_u->xfer_buf; - off /= pmb->pmb_bsize; - len /= pmb->pmb_bsize; - while (0 < len) { - if (0 != blkop(pmb->pmb_pool, buf, off)) { - io_u->error = errno; - break; - } - buf += pmb->pmb_bsize; - off++; - len--; - } - off *= pmb->pmb_bsize; - len *= pmb->pmb_bsize; - io_u->resid = io_u->xfer_buflen - (off - io_u->offset); - break; - case DDIR_SYNC: - case DDIR_DATASYNC: - case DDIR_SYNC_FILE_RANGE: - /* we're always sync'd */ - io_u->error = 0; - break; - default: - io_u->error = EINVAL; - break; - } - - return FIO_Q_COMPLETED; - -} /* fio_pmemblk_queue() */ - - -static int -fio_pmemblk_unlink_file( - struct thread_data* td, - struct fio_file* f -) -{ - char* path = NULL; - uint64_t bsize = 0; - uint64_t fsize = 0; - - /* - * we need our own unlink in case the user has specified - * the block and file sizes in the path name. we parse - * the file_name to determine the file name we actually used. - */ - - pmb_parse_path(f->file_name, &path, &bsize, &fsize); - if (NULL == path) - return 1; - - unlink(path); - free(path); - - return 0; - -} /* fio_pmemblk_unlink_file() */ - - -struct ioengine_ops ioengine = { - .name = "pmemblk", - .version = FIO_IOOPS_VERSION, - .queue = fio_pmemblk_queue, - .open_file = fio_pmemblk_open_file, - .close_file = fio_pmemblk_close_file, - .get_file_size = fio_pmemblk_get_file_size, - .unlink_file = fio_pmemblk_unlink_file, - .flags = FIO_SYNCIO | FIO_DISKLESSIO | FIO_NOEXTEND | FIO_NODISKUTIL, -}; - - -static void -fio_init fio_pmemblk_register(void) -{ - register_ioengine(&ioengine); -} - - -static void -fio_exit fio_pmemblk_unregister(void) -{ - unregister_ioengine(&ioengine); -} -