Recent changes (master)

Jens Axboe
2015-01-14T13:00:06Z

The following changes since commit 36bb0880c7f7f48abb86e3a16d3168343dda9b75:

Fix disk utils being updated too often (2015-01-07 15:04:39 -0700)

are available in the git repository at:

git://git.kernel.dk/fio.git master

for you to fetch changes up to f9a33cc03d70ff34b740629cbde4cef22a120338:

client: take better care to return failure from fio_handle_clients() (2015-01-13 21:47:43 -0700)

----------------------------------------------------------------
Jens Axboe (4):
filelock: fix segfault on some use cases of log file locking
axmap: random maps are private, don't get them from smalloc
smalloc: limit to 1 pool, and bump size to 16MB
client: take better care to return failure from fio_handle_clients()

Yoshinori Sato (1):
mmap backend invalidate fix

client.c | 8 ++-
engines/mmap.c | 25 ++++----
filelock.c | 174 ++++++++++++++++++++++++++++++++++++++++++--------------
lib/axmap.c | 17 +++---
smalloc.c | 4 +-
5 files changed, 158 insertions(+), 70 deletions(-)

---

Diff of recent changes:

diff --git a/client.c b/client.c
index 74c9c76..760ec85 100644
--- a/client.c
+++ b/client.c
@@ -62,6 +62,8 @@ static struct json_object *root = NULL;
static struct json_array *clients_array = NULL;
static struct json_array *du_array = NULL;

+static int error_clients;
+
#define FIO_CLIENT_HASH_BITS 7
#define FIO_CLIENT_HASH_SZ (1 << FIO_CLIENT_HASH_BITS)
#define FIO_CLIENT_HASH_MASK (FIO_CLIENT_HASH_SZ - 1)
@@ -176,6 +178,9 @@ void fio_put_client(struct fio_client *client)
if (!client->did_stat)
sum_stat_clients--;

+ if (client->error)
+ error_clients++;
+
free(client);
}

@@ -1616,6 +1621,7 @@ static int fio_check_clients_timed_out(void)
else
log_err("fio: client %s timed out\n", client->hostname);

+ client->error = ETIMEDOUT;
remove_client(client);
ret = 1;
}
@@ -1709,5 +1715,5 @@ int fio_handle_clients(struct client_ops *ops)
fio_client_json_fini();

free(pfds);
- return retval;
+ return retval || error_clients;
}
diff --git a/engines/mmap.c b/engines/mmap.c
index 8bcd42c..69add78 100644
--- a/engines/mmap.c
+++ b/engines/mmap.c
@@ -62,6 +62,16 @@ static int fio_mmap_file(struct thread_data *td, struct fio_file *f,
goto err;
}
}
+ if (posix_madvise(fmd->mmap_ptr, length, POSIX_MADV_DONTNEED) < 0) {
+ td_verror(td, errno, "madvise");
+ goto err;
+ }
+
+#ifdef FIO_MADV_FREE
+ if (f->filetype == FIO_TYPE_BD)
+ (void) posix_madvise(fmd->mmap_ptr, fmd->mmap_sz, FIO_MADV_FREE);
+#endif
+

err:
if (td->error && fmd->mmap_ptr)
@@ -252,20 +262,6 @@ static int fio_mmapio_close_file(struct thread_data *td, struct fio_file *f)
return generic_close_file(td, f);
}

-static int fio_mmapio_invalidate(struct thread_data *td, struct fio_file *f)
-{
- struct fio_mmap_data *fmd = FILE_ENG_DATA(f);
- int ret;
-
- ret = posix_madvise(fmd->mmap_ptr, fmd->mmap_sz, POSIX_MADV_DONTNEED);
-#ifdef FIO_MADV_FREE
- if (f->filetype == FIO_TYPE_BD)
- (void) posix_madvise(fmd->mmap_ptr, fmd->mmap_sz, FIO_MADV_FREE);
-#endif
-
- return ret;
-}
-
static struct ioengine_ops ioengine = {
.name = "mmap",
.version = FIO_IOOPS_VERSION,
@@ -274,7 +270,6 @@ static struct ioengine_ops ioengine = {
.queue = fio_mmapio_queue,
.open_file = fio_mmapio_open_file,
.close_file = fio_mmapio_close_file,
- .invalidate = fio_mmapio_invalidate,
.get_file_size = generic_get_file_size,
.flags = FIO_SYNCIO | FIO_NOEXTEND,
};
diff --git a/filelock.c b/filelock.c
index 18e8875..17b5a85 100644
--- a/filelock.c
+++ b/filelock.c
@@ -5,6 +5,7 @@
*/
#include <inttypes.h>
#include <string.h>
+#include <unistd.h>
#include <assert.h>

#include "flist.h"
@@ -20,36 +21,99 @@ struct fio_filelock {
struct flist_head list;
unsigned int references;
};
+
+#define MAX_FILELOCKS 128

-static struct flist_head *filelock_list;
-static struct fio_mutex *filelock_lock;
+static struct filelock_data {
+ struct flist_head list;
+ struct fio_mutex lock;
+
+ struct flist_head free_list;
+ struct fio_filelock ffs[MAX_FILELOCKS];
+} *fld;
+
+static void put_filelock(struct fio_filelock *ff)
+{
+ flist_add(&ff->list, &fld->free_list);
+}
+
+static struct fio_filelock *__get_filelock(void)
+{
+ struct fio_filelock *ff;
+
+ if (flist_empty(&fld->free_list))
+ return NULL;
+
+ ff = flist_first_entry(&fld->free_list, struct fio_filelock, list);
+ flist_del_init(&ff->list);
+ return ff;
+}
+
+static struct fio_filelock *get_filelock(int trylock, int *retry)
+{
+ struct fio_filelock *ff;
+
+ do {
+ ff = __get_filelock();
+ if (ff || trylock)
+ break;
+
+ fio_mutex_up(&fld->lock);
+ usleep(1000);
+ fio_mutex_down(&fld->lock);
+ *retry = 1;
+ } while (1);
+
+ return ff;
+}

int fio_filelock_init(void)
{
- filelock_list = smalloc(sizeof(*filelock_list));
- if (!filelock_list)
- return 1;
+ int i;

- INIT_FLIST_HEAD(filelock_list);
- filelock_lock = fio_mutex_init(FIO_MUTEX_UNLOCKED);
- if (!filelock_lock) {
- sfree(filelock_list);
+ fld = smalloc(sizeof(*fld));
+ if (!fld)
return 1;
+
+ INIT_FLIST_HEAD(&fld->list);
+ INIT_FLIST_HEAD(&fld->free_list);
+
+ if (__fio_mutex_init(&fld->lock, FIO_MUTEX_UNLOCKED))
+ goto err;
+
+ for (i = 0; i < MAX_FILELOCKS; i++) {
+ struct fio_filelock *ff = &fld->ffs[i];
+
+ if (__fio_mutex_init(&ff->lock, FIO_MUTEX_UNLOCKED))
+ goto err;
+ flist_add_tail(&ff->list, &fld->free_list);
}

return 0;
+err:
+ fio_filelock_exit();
+ return 1;
}

void fio_filelock_exit(void)
{
- if (!filelock_list)
+ if (!fld)
return;

- assert(flist_empty(filelock_list));
- sfree(filelock_list);
- filelock_list = NULL;
- fio_mutex_remove(filelock_lock);
- filelock_lock = NULL;
+ assert(flist_empty(&fld->list));
+ fio_mutex_remove(&fld->lock);
+
+ while (!flist_empty(&fld->free_list)) {
+ struct fio_filelock *ff;
+
+ ff = flist_first_entry(&fld->free_list, struct fio_filelock, list);
+
+ flist_del_init(&ff->list);
+ fio_mutex_remove(&ff->lock);
+ }
+
+ sfree(fld);
+ fld = NULL;
}

static struct fio_filelock *fio_hash_find(uint32_t hash)
@@ -57,7 +121,7 @@ static struct fio_filelock *fio_hash_find(uint32_t hash)
struct flist_head *entry;
struct fio_filelock *ff;

- flist_for_each(entry, filelock_list) {
+ flist_for_each(entry, &fld->list) {
ff = flist_entry(entry, struct fio_filelock, list);
if (ff->hash == hash)
return ff;
@@ -66,38 +130,68 @@ static struct fio_filelock *fio_hash_find(uint32_t hash)
return NULL;
}

-static struct fio_filelock *fio_hash_get(uint32_t hash)
+static struct fio_filelock *fio_hash_get(uint32_t hash, int trylock)
{
struct fio_filelock *ff;

ff = fio_hash_find(hash);
if (!ff) {
- ff = smalloc(sizeof(*ff));
+ int retry = 0;
+
+ ff = get_filelock(trylock, &retry);
+ if (!ff)
+ return NULL;
+
+ /*
+ * If we dropped the main lock, re-lookup the hash in case
+ * someone else added it meanwhile. If it's now there,
+ * just return that.
+ */
+ if (retry) {
+ struct fio_filelock *__ff;
+
+ __ff = fio_hash_find(hash);
+ if (__ff) {
+ put_filelock(ff);
+ return __ff;
+ }
+ }
+
ff->hash = hash;
- __fio_mutex_init(&ff->lock, FIO_MUTEX_UNLOCKED);
ff->references = 0;
- flist_add(&ff->list, filelock_list);
+ flist_add(&ff->list, &fld->list);
}

return ff;
}

-int fio_trylock_file(const char *fname)
+static int __fio_lock_file(const char *fname, int trylock)
{
struct fio_filelock *ff;
uint32_t hash;

hash = jhash(fname, strlen(fname), 0);

- fio_mutex_down(filelock_lock);
- ff = fio_hash_get(hash);
- ff->references++;
- fio_mutex_up(filelock_lock);
+ fio_mutex_down(&fld->lock);
+ ff = fio_hash_get(hash, trylock);
+ if (ff)
+ ff->references++;
+ fio_mutex_up(&fld->lock);
+
+ if (!ff) {
+ assert(!trylock);
+ return 1;
+ }
+
+ if (!trylock) {
+ fio_mutex_down(&ff->lock);
+ return 0;
+ }

if (!fio_mutex_down_trylock(&ff->lock))
return 0;

- fio_mutex_down(filelock_lock);
+ fio_mutex_down(&fld->lock);

/*
* If we raced and the only reference to the lock is us, we can
@@ -108,7 +202,7 @@ int fio_trylock_file(const char *fname)
ff = NULL;
}

- fio_mutex_up(filelock_lock);
+ fio_mutex_up(&fld->lock);

if (ff) {
fio_mutex_down(&ff->lock);
@@ -118,19 +212,14 @@ int fio_trylock_file(const char *fname)
return 1;
}

-void fio_lock_file(const char *fname)
+int fio_trylock_file(const char *fname)
{
- struct fio_filelock *ff;
- uint32_t hash;
-
- hash = jhash(fname, strlen(fname), 0);
-
- fio_mutex_down(filelock_lock);
- ff = fio_hash_get(hash);
- ff->references++;
- fio_mutex_up(filelock_lock);
+ return __fio_lock_file(fname, 1);
+}

- fio_mutex_down(&ff->lock);
+void fio_lock_file(const char *fname)
+{
+ __fio_lock_file(fname, 0);
}

void fio_unlock_file(const char *fname)
@@ -140,19 +229,18 @@ void fio_unlock_file(const char *fname)

hash = jhash(fname, strlen(fname), 0);

- fio_mutex_down(filelock_lock);
+ fio_mutex_down(&fld->lock);

ff = fio_hash_find(hash);
if (ff) {
int refs = --ff->references;
fio_mutex_up(&ff->lock);
if (!refs) {
- flist_del(&ff->list);
- __fio_mutex_remove(&ff->lock);
- sfree(ff);
+ flist_del_init(&ff->list);
+ put_filelock(ff);
}
} else
log_err("fio: file not found for unlocking\n");

- fio_mutex_up(filelock_lock);
+ fio_mutex_up(&fld->lock);
}
diff --git a/lib/axmap.c b/lib/axmap.c
index 68096d8..164300f 100644
--- a/lib/axmap.c
+++ b/lib/axmap.c
@@ -22,7 +22,6 @@

#include "../arch/arch.h"
#include "axmap.h"
-#include "../smalloc.h"
#include "../minmax.h"

#if BITS_PER_LONG == 64
@@ -80,10 +79,10 @@ void axmap_free(struct axmap *axmap)
return;

for (i = 0; i < axmap->nr_levels; i++)
- sfree(axmap->levels[i].map);
+ free(axmap->levels[i].map);

- sfree(axmap->levels);
- sfree(axmap);
+ free(axmap->levels);
+ free(axmap);
}

struct axmap *axmap_new(unsigned long nr_bits)
@@ -91,7 +90,7 @@ struct axmap *axmap_new(unsigned long nr_bits)
struct axmap *axmap;
unsigned int i, levels;

- axmap = smalloc(sizeof(*axmap));
+ axmap = malloc(sizeof(*axmap));
if (!axmap)
return NULL;

@@ -103,7 +102,7 @@ struct axmap *axmap_new(unsigned long nr_bits)
}

axmap->nr_levels = levels;
- axmap->levels = smalloc(axmap->nr_levels * sizeof(struct axmap_level));
+ axmap->levels = malloc(axmap->nr_levels * sizeof(struct axmap_level));
axmap->nr_bits = nr_bits;

for (i = 0; i < axmap->nr_levels; i++) {
@@ -111,7 +110,7 @@ struct axmap *axmap_new(unsigned long nr_bits)

al->level = i;
al->map_size = (nr_bits + BLOCKS_PER_UNIT - 1) >> UNIT_SHIFT;
- al->map = smalloc(al->map_size * sizeof(unsigned long));
+ al->map = malloc(al->map_size * sizeof(unsigned long));
if (!al->map)
goto err;

@@ -123,9 +122,9 @@ struct axmap *axmap_new(unsigned long nr_bits)
err:
for (i = 0; i < axmap->nr_levels; i++)
if (axmap->levels[i].map)
- sfree(axmap->levels[i].map);
+ free(axmap->levels[i].map);

- sfree(axmap->levels);
+ free(axmap->levels);
return NULL;
}

diff --git a/smalloc.c b/smalloc.c
index 1ba9353..67cb7cc 100644
--- a/smalloc.c
+++ b/smalloc.c
@@ -25,8 +25,8 @@
#define SMALLOC_BPI (sizeof(unsigned int) * 8)
#define SMALLOC_BPL (SMALLOC_BPB * SMALLOC_BPI)

-#define INITIAL_SIZE 8192*1024 /* new pool size */
-#define MAX_POOLS 128 /* maximum number of pools to setup */
+#define INITIAL_SIZE 16*1024*1024 /* new pool size */
+#define MAX_POOLS 1 /* maximum number of pools to setup */

#define SMALLOC_PRE_RED 0xdeadbeefU
#define SMALLOC_POST_RED 0x5aa55aa5U