Allow prof.dump mallctl to specify filename.
diff --git a/jemalloc/doc/jemalloc.3.in b/jemalloc/doc/jemalloc.3.in
index 6e55ca0..306b569 100644
--- a/jemalloc/doc/jemalloc.3.in
+++ b/jemalloc/doc/jemalloc.3.in
@@ -1016,9 +1016,10 @@
 Maximum size supported by this large size class.
 .Ed
 .\"-----------------------------------------------------------------------------
-@roff_prof@.It Sy "prof.dump (void) --"
+@roff_prof@.It Sy "prof.dump (const char *) -w"
 @roff_prof@.Bd -ragged -offset indent -compact
-@roff_prof@Dump a memory profile to a file according to the pattern
+@roff_prof@Dump a memory profile to the specified file, or if NULL is specified,
+@roff_prof@to a file according to the pattern
 @roff_prof@.Pa <prefix>.<pid>.<seq>.m<mseq>.heap ,
 @roff_prof@where
 @roff_prof@.Pa <prefix>
diff --git a/jemalloc/include/jemalloc/internal/prof.h b/jemalloc/include/jemalloc/internal/prof.h
index 364ac0a..e29a574 100644
--- a/jemalloc/include/jemalloc/internal/prof.h
+++ b/jemalloc/include/jemalloc/internal/prof.h
@@ -144,7 +144,7 @@
     size_t old_size, prof_thr_cnt_t *old_cnt);
 void	prof_free(const void *ptr);
 void	prof_idump(void);
-void	prof_mdump(void);
+bool	prof_mdump(const char *filename);
 void	prof_udump(void);
 void	prof_boot0(void);
 bool	prof_boot1(void);
diff --git a/jemalloc/src/ctl.c b/jemalloc/src/ctl.c
index 36411e0..aa7e53d 100644
--- a/jemalloc/src/ctl.c
+++ b/jemalloc/src/ctl.c
@@ -830,14 +830,18 @@
 	}								\
 } while (0)
 
-#define	VOID()	do {							\
-	READONLY();							\
+#define	WRITEONLY()	do {						\
 	if (oldp != NULL || oldlenp != NULL) {				\
 		ret = EPERM;						\
 		goto RETURN;						\
 	}								\
 } while (0)
 
+#define	VOID()	do {							\
+	READONLY();							\
+	WRITEONLY();							\
+} while (0)
+
 #define	READ(v, t)	do {						\
 	if (oldp != NULL && oldlenp != NULL) {				\
 		if (*oldlenp != sizeof(t)) {				\
@@ -1167,10 +1171,15 @@
     void *newp, size_t newlen)
 {
 	int ret;
+	const char *filename = NULL;
 
-	VOID();
+	WRITEONLY();
+	WRITE(filename, const char *);
 
-	prof_mdump();
+	if (prof_mdump(filename)) {
+		ret = EFAULT;
+		goto RETURN;
+	}
 
 	ret = 0;
 RETURN:
diff --git a/jemalloc/src/prof.c b/jemalloc/src/prof.c
index d44084f..a83314e 100644
--- a/jemalloc/src/prof.c
+++ b/jemalloc/src/prof.c
@@ -99,13 +99,15 @@
 static void	prof_backtrace(prof_bt_t *bt, unsigned nignore, unsigned max);
 static prof_thr_cnt_t	*prof_lookup(prof_bt_t *bt);
 static void	prof_cnt_set(const void *ptr, prof_thr_cnt_t *cnt);
-static void	prof_flush(void);
-static void	prof_write(const char *s);
+static bool	prof_flush(bool propagate_err);
+static bool	prof_write(const char *s, bool propagate_err);
 static void	prof_ctx_merge(prof_ctx_t *ctx, prof_cnt_t *cnt_all,
     size_t *leak_nctx);
-static void	prof_dump_ctx(prof_ctx_t *ctx, prof_bt_t *bt);
-static void	prof_dump_maps(void);
-static void	prof_dump(const char *filename, bool leakcheck);
+static bool	prof_dump_ctx(prof_ctx_t *ctx, prof_bt_t *bt,
+    bool propagate_err);
+static bool	prof_dump_maps(bool propagate_err);
+static bool	prof_dump(const char *filename, bool leakcheck,
+    bool propagate_err);
 static void	prof_dump_filename(char *filename, char v, int64_t vseq);
 static void	prof_fdump(void);
 static void	prof_bt_hash(const void *key, unsigned minbits, size_t *hash1,
@@ -715,23 +717,30 @@
 	}
 }
 
-static void
-prof_flush(void)
+static bool
+prof_flush(bool propagate_err)
 {
+	bool ret = false;
 	ssize_t err;
 
 	err = write(prof_dump_fd, prof_dump_buf, prof_dump_buf_end);
 	if (err == -1) {
-		malloc_write4("<jemalloc>",
-		    ": write() failed during heap profile flush", "\n", "");
-		if (opt_abort)
-			abort();
+		if (propagate_err == false) {
+			malloc_write4("<jemalloc>",
+			    ": write() failed during heap profile flush", "\n",
+			    "");
+			if (opt_abort)
+				abort();
+		}
+		ret = true;
 	}
 	prof_dump_buf_end = 0;
+
+	return (ret);
 }
 
-static void
-prof_write(const char *s)
+static bool
+prof_write(const char *s, bool propagate_err)
 {
 	unsigned i, slen, n;
 
@@ -740,7 +749,8 @@
 	while (i < slen) {
 		/* Flush the buffer if it is full. */
 		if (prof_dump_buf_end == PROF_DUMP_BUF_SIZE)
-			prof_flush();
+			if (prof_flush(propagate_err) && propagate_err)
+				return (true);
 
 		if (prof_dump_buf_end + slen <= PROF_DUMP_BUF_SIZE) {
 			/* Finish writing. */
@@ -753,6 +763,8 @@
 		prof_dump_buf_end += n;
 		i += n;
 	}
+
+	return (false);
 }
 
 static void
@@ -799,31 +811,40 @@
 	malloc_mutex_unlock(&ctx->lock);
 }
 
-static void
-prof_dump_ctx(prof_ctx_t *ctx, prof_bt_t *bt)
+static bool
+prof_dump_ctx(prof_ctx_t *ctx, prof_bt_t *bt, bool propagate_err)
 {
 	char buf[UMAX2S_BUFSIZE];
 	unsigned i;
 
-	prof_write(umax2s(ctx->cnt_dump.curobjs, 10, buf));
-	prof_write(": ");
-	prof_write(umax2s(ctx->cnt_dump.curbytes, 10, buf));
-	prof_write(" [");
-	prof_write(umax2s(ctx->cnt_dump.accumobjs, 10, buf));
-	prof_write(": ");
-	prof_write(umax2s(ctx->cnt_dump.accumbytes, 10, buf));
-	prof_write("] @");
+	if (prof_write(umax2s(ctx->cnt_dump.curobjs, 10, buf), propagate_err)
+	    || prof_write(": ", propagate_err)
+	    || prof_write(umax2s(ctx->cnt_dump.curbytes, 10, buf),
+	    propagate_err)
+	    || prof_write(" [", propagate_err)
+	    || prof_write(umax2s(ctx->cnt_dump.accumobjs, 10, buf),
+	    propagate_err)
+	    || prof_write(": ", propagate_err)
+	    || prof_write(umax2s(ctx->cnt_dump.accumbytes, 10, buf),
+	    propagate_err)
+	    || prof_write("] @", propagate_err))
+		return (true);
 
 	for (i = 0; i < bt->len; i++) {
-		prof_write(" 0x");
-		prof_write(umax2s((uintptr_t)bt->vec[i], 16, buf));
+		if (prof_write(" 0x", propagate_err)
+		    || prof_write(umax2s((uintptr_t)bt->vec[i], 16, buf),
+		    propagate_err))
+			return (true);
 	}
 
-	prof_write("\n");
+	if (prof_write("\n", propagate_err))
+		return (true);
+
+	return (false);
 }
 
-static void
-prof_dump_maps(void)
+static bool
+prof_dump_maps(bool propagate_err)
 {
 	int mfd;
 	char buf[UMAX2S_BUFSIZE];
@@ -856,23 +877,29 @@
 	if (mfd != -1) {
 		ssize_t nread;
 
-		prof_write("\nMAPPED_LIBRARIES:\n");
+		if (prof_write("\nMAPPED_LIBRARIES:\n", propagate_err) &&
+		    propagate_err)
+			return (true);
 		nread = 0;
 		do {
 			prof_dump_buf_end += nread;
 			if (prof_dump_buf_end == PROF_DUMP_BUF_SIZE) {
 				/* Make space in prof_dump_buf before read(). */
-				prof_flush();
+				if (prof_flush(propagate_err) && propagate_err)
+					return (true);
 			}
 			nread = read(mfd, &prof_dump_buf[prof_dump_buf_end],
 			    PROF_DUMP_BUF_SIZE - prof_dump_buf_end);
 		} while (nread > 0);
 		close(mfd);
-	}
+	} else
+		return (true);
+
+	return (false);
 }
 
-static void
-prof_dump(const char *filename, bool leakcheck)
+static bool
+prof_dump(const char *filename, bool leakcheck, bool propagate_err)
 {
 	prof_cnt_t cnt_all;
 	size_t tabind;
@@ -884,12 +911,14 @@
 	prof_enter();
 	prof_dump_fd = creat(filename, 0644);
 	if (prof_dump_fd == -1) {
-		malloc_write4("<jemalloc>",
-		    ": creat(\"", filename, "\", 0644) failed\n");
-		if (opt_abort)
-			abort();
+		if (propagate_err == false) {
+			malloc_write4("<jemalloc>",
+			    ": creat(\"", filename, "\", 0644) failed\n");
+			if (opt_abort)
+				abort();
+		}
 		prof_leave();
-		return;
+		goto ERROR;
 	}
 
 	/* Merge per thread profile stats, and sum them in cnt_all. */
@@ -901,32 +930,40 @@
 	}
 
 	/* Dump profile header. */
-	prof_write("heap profile: ");
-	prof_write(umax2s(cnt_all.curobjs, 10, buf));
-	prof_write(": ");
-	prof_write(umax2s(cnt_all.curbytes, 10, buf));
-	prof_write(" [");
-	prof_write(umax2s(cnt_all.accumobjs, 10, buf));
-	prof_write(": ");
-	prof_write(umax2s(cnt_all.accumbytes, 10, buf));
-	if (opt_lg_prof_sample == 0)
-		prof_write("] @ heapprofile\n");
-	else {
-		prof_write("] @ heap_v2/");
-		prof_write(umax2s((uint64_t)1U << opt_lg_prof_sample, 10, buf));
-		prof_write("\n");
+	if (prof_write("heap profile: ", propagate_err)
+	    || prof_write(umax2s(cnt_all.curobjs, 10, buf), propagate_err)
+	    || prof_write(": ", propagate_err)
+	    || prof_write(umax2s(cnt_all.curbytes, 10, buf), propagate_err)
+	    || prof_write(" [", propagate_err)
+	    || prof_write(umax2s(cnt_all.accumobjs, 10, buf), propagate_err)
+	    || prof_write(": ", propagate_err)
+	    || prof_write(umax2s(cnt_all.accumbytes, 10, buf), propagate_err))
+		goto ERROR;
+
+	if (opt_lg_prof_sample == 0) {
+		if (prof_write("] @ heapprofile\n", propagate_err))
+			goto ERROR;
+	} else {
+		if (prof_write("] @ heap_v2/", propagate_err)
+		    || prof_write(umax2s((uint64_t)1U << opt_lg_prof_sample, 10,
+		    buf), propagate_err)
+		    || prof_write("\n", propagate_err))
+			goto ERROR;
 	}
 
 	/* Dump  per ctx profile stats. */
 	for (tabind = 0; ckh_iter(&bt2ctx, &tabind, (void **)&bt, (void **)&ctx)
 	    == false;) {
-		prof_dump_ctx(ctx, bt);
+		if (prof_dump_ctx(ctx, bt, propagate_err))
+			goto ERROR;
 	}
 
 	/* Dump /proc/<pid>/maps if possible. */
-	prof_dump_maps();
+	if (prof_dump_maps(propagate_err))
+		goto ERROR;
 
-	prof_flush();
+	if (prof_flush(propagate_err))
+		goto ERROR;
 	close(prof_dump_fd);
 	prof_leave();
 
@@ -941,6 +978,11 @@
 		malloc_write4("<jemalloc>: Run pprof on \"",
 		    filename, "\" for leak detail\n", "");
 	}
+
+	return (false);
+ERROR:
+	prof_leave();
+	return (true);
 }
 
 #define	DUMP_FILENAME_BUFSIZE	(PATH_MAX+ UMAX2S_BUFSIZE		\
@@ -1034,7 +1076,7 @@
 	malloc_mutex_lock(&prof_dump_seq_mtx);
 	prof_dump_filename(filename, 'f', 0xffffffffffffffffLLU);
 	malloc_mutex_unlock(&prof_dump_seq_mtx);
-	prof_dump(filename, opt_prof_leak);
+	prof_dump(filename, opt_prof_leak, false);
 }
 
 void
@@ -1056,22 +1098,26 @@
 	prof_dump_filename(filename, 'i', prof_dump_iseq);
 	prof_dump_iseq++;
 	malloc_mutex_unlock(&prof_dump_seq_mtx);
-	prof_dump(filename, false);
+	prof_dump(filename, false, false);
 }
 
-void
-prof_mdump(void)
+bool
+prof_mdump(const char *filename)
 {
-	char filename[DUMP_FILENAME_BUFSIZE];
+	char filename_buf[DUMP_FILENAME_BUFSIZE];
 
-	if (prof_booted == false)
-		return;
+	if (opt_prof == false || prof_booted == false)
+		return (true);
 
-	malloc_mutex_lock(&prof_dump_seq_mtx);
-	prof_dump_filename(filename, 'm', prof_dump_mseq);
-	prof_dump_mseq++;
-	malloc_mutex_unlock(&prof_dump_seq_mtx);
-	prof_dump(filename, false);
+	if (filename == NULL) {
+		/* No filename specified, so automatically generate one. */
+		malloc_mutex_lock(&prof_dump_seq_mtx);
+		prof_dump_filename(filename_buf, 'm', prof_dump_mseq);
+		prof_dump_mseq++;
+		malloc_mutex_unlock(&prof_dump_seq_mtx);
+		filename = filename_buf;
+	}
+	return (prof_dump(filename, false, true));
 }
 
 void
@@ -1093,7 +1139,7 @@
 	prof_dump_filename(filename, 'u', prof_dump_useq);
 	prof_dump_useq++;
 	malloc_mutex_unlock(&prof_dump_seq_mtx);
-	prof_dump(filename, false);
+	prof_dump(filename, false, false);
 }
 
 static void