[PATCH] Split out the memory handling from fio.c

In the process also fix some bugs in the memory pinning.

Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
diff --git a/Makefile b/Makefile
index a3e215e..111d5cd 100644
--- a/Makefile
+++ b/Makefile
@@ -2,6 +2,8 @@
 CFLAGS	= -W -Wall -O2 -g -D_GNU_SOURCE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
 PROGS	= fio
 SCRIPTS = fio_generate_plots
+OBJS = fio.o ioengines.o init.o stat.o log.o time.o md5.o crc32.o \
+	filesetup.o eta.o verify.o memory.o
 
 INSTALL = install
 prefix = /usr/local
@@ -15,7 +17,7 @@
 all: depend $(PROGS) $(SCRIPTS)
 	$(MAKE) -C engines
 
-fio: fio.o ioengines.o init.o stat.o log.o time.o md5.o crc32.o filesetup.o eta.o verify.o
+fio: $(OBJS)
 	$(CC) $(CFLAGS) -o $@ $(filter %.o,$^) -lpthread -lm -ldl
 
 clean:
diff --git a/fio.c b/fio.c
index 624c959..8d2a8e5 100644
--- a/fio.c
+++ b/fio.c
@@ -45,8 +45,6 @@
 int temp_stall_ts;
 char *fio_inst_prefix = _INST_PREFIX;
 
-extern unsigned long long mlock_size;
-
 #define should_fsync(td)	((td_write(td) || td_rw(td)) && (!(td)->odirect || (td)->override_sync))
 
 static volatile int startup_sem;
@@ -237,8 +235,6 @@
 		rate = (td->this_io_bytes[ddir] - td->rate_bytes) / spent;
 		if (rate < td->ratemin) {
 			fprintf(f_out, "%s: min rate %d not met, got %ldKiB/sec\n", td->name, td->ratemin, rate);
-			if (rate_quit)
-				terminate_threads(td->groupid);
 			return 1;
 		}
 	}
@@ -753,6 +749,8 @@
 		rate_throttle(td, usec, icd.bytes_done[td->ddir]);
 
 		if (check_min_rate(td, &e)) {
+			if (rate_quit)
+				terminate_threads(td->groupid);
 			td_verror(td, ENOMEM);
 			break;
 		}
@@ -800,19 +798,7 @@
 		free(io_u);
 	}
 
-	if (td->mem_type == MEM_MALLOC)
-		free(td->orig_buffer);
-	else if (td->mem_type == MEM_SHM) {
-		struct shmid_ds sbuf;
-
-		shmdt(td->orig_buffer);
-		shmctl(td->shm_id, IPC_RMID, &sbuf);
-	} else if (td->mem_type == MEM_MMAP)
-		munmap(td->orig_buffer, td->orig_buffer_size);
-	else
-		log_err("Bad memory type %d\n", td->mem_type);
-
-	td->orig_buffer = NULL;
+	free_io_mem(td);
 }
 
 static int init_io_u(struct thread_data *td)
@@ -831,32 +817,8 @@
 
 	td->orig_buffer_size = td->max_bs * max_units + MASK;
 
-	if (td->mem_type == MEM_MALLOC)
-		td->orig_buffer = malloc(td->orig_buffer_size);
-	else if (td->mem_type == MEM_SHM) {
-		td->shm_id = shmget(IPC_PRIVATE, td->orig_buffer_size, IPC_CREAT | 0600);
-		if (td->shm_id < 0) {
-			td_verror(td, errno);
-			perror("shmget");
-			return 1;
-		}
-
-		td->orig_buffer = shmat(td->shm_id, NULL, 0);
-		if (td->orig_buffer == (void *) -1) {
-			td_verror(td, errno);
-			perror("shmat");
-			td->orig_buffer = NULL;
-			return 1;
-		}
-	} else if (td->mem_type == MEM_MMAP) {
-		td->orig_buffer = mmap(NULL, td->orig_buffer_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | OS_MAP_ANON, 0, 0);
-		if (td->orig_buffer == MAP_FAILED) {
-			td_verror(td, errno);
-			perror("mmap");
-			td->orig_buffer = NULL;
-			return 1;
-		}
-	}
+	if (allocate_io_mem(td))
+		return 1;
 
 	p = ALIGN(td->orig_buffer);
 	for (i = 0; i < max_units; i++) {
@@ -1126,48 +1088,6 @@
 		terminate_threads(TERMINATE_ALL);
 }
 
-static void fio_unpin_memory(void *pinned)
-{
-	if (pinned) {
-		if (munlock(pinned, mlock_size) < 0)
-			perror("munlock");
-		munmap(pinned, mlock_size);
-	}
-}
-
-static void *fio_pin_memory(void)
-{
-	unsigned long long phys_mem;
-	void *ptr;
-
-	if (!mlock_size)
-		return NULL;
-
-	/*
-	 * Don't allow mlock of more than real_mem-128MB
-	 */
-	phys_mem = os_phys_mem();
-	if (phys_mem) {
-		if ((mlock_size + 128 * 1024 * 1024) > phys_mem) {
-			mlock_size = phys_mem - 128 * 1024 * 1024;
-			fprintf(f_out, "fio: limiting mlocked memory to %lluMiB\n", mlock_size >> 20);
-		}
-	}
-
-	ptr = mmap(NULL, mlock_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | OS_MAP_ANON, 0, 0);
-	if (!ptr) {
-		perror("malloc locked mem");
-		return NULL;
-	}
-	if (mlock(ptr, mlock_size) < 0) {
-		munmap(ptr, mlock_size);
-		perror("mlock");
-		return NULL;
-	}
-
-	return ptr;
-}
-
 /*
  * Main function for kicking off and reaping jobs, as needed.
  */
@@ -1176,9 +1096,9 @@
 	struct thread_data *td;
 	unsigned long spent;
 	int i, todo, nr_running, m_rate, t_rate, nr_started;
-	void *mlocked_mem;
 
-	mlocked_mem = fio_pin_memory();
+	if (fio_pin_memory())
+		return;
 
 	if (!terse_output) {
 		printf("Starting %d thread%s\n", thread_number, thread_number > 1 ? "s" : "");
@@ -1336,7 +1256,7 @@
 	}
 
 	update_io_ticks();
-	fio_unpin_memory(mlocked_mem);
+	fio_unpin_memory();
 }
 
 int main(int argc, char *argv[])
diff --git a/fio.h b/fio.h
index 4af6a74..b9ae15b 100644
--- a/fio.h
+++ b/fio.h
@@ -480,6 +480,14 @@
 extern int do_io_u_verify(struct thread_data *, struct io_u **);
 
 /*
+ * Memory helpers
+ */
+extern int fio_pin_memory(void);
+extern void fio_unpin_memory(void);
+extern int allocate_io_mem(struct thread_data *);
+extern void free_io_mem(struct thread_data *);
+
+/*
  * This is a pretty crappy semaphore implementation, but with the use that fio
  * has (just signalling start/go conditions), it doesn't have to be better.
  * Naturally this would not work for any type of contended semaphore or
diff --git a/memory.c b/memory.c
new file mode 100644
index 0000000..d8924a8
--- /dev/null
+++ b/memory.c
@@ -0,0 +1,108 @@
+/*
+ * Memory helpers
+ */
+#include <unistd.h>
+#include <sys/shm.h>
+#include <sys/mman.h>
+
+#include "fio.h"
+#include "os.h"
+
+extern unsigned long long mlock_size;
+static void *pinned_mem;
+
+void fio_unpin_memory(void)
+{
+	if (pinned_mem) {
+		if (munlock(pinned_mem, mlock_size) < 0)
+			perror("munlock");
+		munmap(pinned_mem, mlock_size);
+		pinned_mem = NULL;
+	}
+}
+
+int fio_pin_memory(void)
+{
+	unsigned long long phys_mem;
+
+	if (!mlock_size)
+		return 0;
+
+	/*
+	 * Don't allow mlock of more than real_mem-128MB
+	 */
+	phys_mem = os_phys_mem();
+	if (phys_mem) {
+		if ((mlock_size + 128 * 1024 * 1024) > phys_mem) {
+			mlock_size = phys_mem - 128 * 1024 * 1024;
+			fprintf(f_out, "fio: limiting mlocked memory to %lluMiB\n", mlock_size >> 20);
+		}
+	}
+
+	pinned_mem = mmap(NULL, mlock_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | OS_MAP_ANON, 0, 0);
+	if (pinned_mem == MAP_FAILED) {
+		perror("malloc locked mem");
+		pinned_mem = NULL;
+		return 1;
+	}
+	if (mlock(pinned_mem, mlock_size) < 0) {
+		perror("mlock");
+		munmap(pinned_mem, mlock_size);
+		pinned_mem = NULL;
+		return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * Setup the buffer area we need for io.
+ */
+int allocate_io_mem(struct thread_data *td)
+{
+	if (td->mem_type == MEM_MALLOC)
+		td->orig_buffer = malloc(td->orig_buffer_size);
+	else if (td->mem_type == MEM_SHM) {
+		td->shm_id = shmget(IPC_PRIVATE, td->orig_buffer_size, IPC_CREAT | 0600);
+		if (td->shm_id < 0) {
+			td_verror(td, errno);
+			perror("shmget");
+			return 1;
+		}
+
+		td->orig_buffer = shmat(td->shm_id, NULL, 0);
+		if (td->orig_buffer == (void *) -1) {
+			td_verror(td, errno);
+			perror("shmat");
+			td->orig_buffer = NULL;
+			return 1;
+		}
+	} else if (td->mem_type == MEM_MMAP) {
+		td->orig_buffer = mmap(NULL, td->orig_buffer_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | OS_MAP_ANON, 0, 0);
+		if (td->orig_buffer == MAP_FAILED) {
+			td_verror(td, errno);
+			perror("mmap");
+			td->orig_buffer = NULL;
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+void free_io_mem(struct thread_data *td)
+{
+	if (td->mem_type == MEM_MALLOC)
+		free(td->orig_buffer);
+	else if (td->mem_type == MEM_SHM) {
+		struct shmid_ds sbuf;
+
+		shmdt(td->orig_buffer);
+		shmctl(td->shm_id, IPC_RMID, &sbuf);
+	} else if (td->mem_type == MEM_MMAP)
+		munmap(td->orig_buffer, td->orig_buffer_size);
+	else
+		log_err("Bad memory type %d\n", td->mem_type);
+
+	td->orig_buffer = NULL;
+}